Package net.jini.security

Provides mechanisms and abstractions for managing security, especially in the presence of dynamically downloaded code.

See: Description

Package net.jini.security Description

Provides mechanisms and abstractions for managing security, especially in the presence of dynamically downloaded code. The mechanisms include:

Programming Model

When a client obtains a proxy from somewhere, normally the client should follow these three steps before making any remote calls through the proxy or handing any sensitive data to the proxy: The first step can be accomplished using Security.verifyObjectTrust. The second step can be accomplished using RemoteMethodControl.setConstraints; BasicMethodConstraints is a basic implementation of MethodConstraints. The last step can be accomplished using Security.grant.

Normally the client should be written in such a way that it can be configured to allow for variations in the steps used to prepare a proxy for subsequent use. The usual way is to obtain a ProxyPreparer from a Configuration, using as a default value a BasicProxyPreparer that simply returns the proxy. The client can then be configured at deployment time to perform whatever steps are desired.

Configuration config = ...;
SomeService proxy = ...;
ProxyPreparer preparer = (ProxyPreparer) config.getEntry(
                                "MyClient", "someServicePreparer",
                                ProxyPreparer.class, new BasicProxyPreparer());
proxy = (SomeService) preparer.prepareProxy(proxy);

BasicProxyPreparer can be used to perform all combinations of these three common steps of proxy preparation.

Proxy Trust

The basic proxy trust issue can be seen with an example. Suppose the client wants to make a remote call through a proxy. The proxy implements the RemoteMethodControl interface, and the client attaches constraints to the proxy, requiring the server to authenticate as a particular principal. If the proxy code has been dynamically downloaded, and the client does nothing to verify that it trusts the proxy, then the downloaded code might simply ignore the client's constraints and perform no authentication at all. The proxy code might also corrupt the data being passed in the call, or perform some other unintended operation.

The client needs some way to decide that it trusts a proxy. Rather than mandating any specific mechanism(s), a pluggable framework is provided. The client calls Security.verifyObjectTrust, passing the proxy and a caller context collection that typically contains a MethodConstraints instance. This method uses whatever TrustVerifier instances have been configured to determine if the proxy can be trusted; if any verifier says that it trusts the proxy, then the proxy is assumed to be trusted. If no verifier trusts the proxy, a SecurityException is thrown. The caller context collection contains whatever context information might be required by verifiers; a MethodConstraints element in the collection is typically used to control any calls to the remote server that are made by verifiers.

A baseline for deciding a proxy can be trusted is to examine the proxy and all of its constituent objects, excluding the client constraints, to ensure that they are all instances of locally trusted (typically, not downloaded) classes, containing trusted data. For example, BasicJeriTrustVerifier provides this baseline for basic dynamic proxies of remote objects exported to use Jini extensible remote invocation (Jini ERI), in conjunction with ConstraintTrustVerifier, which verifies the standard constraints. ProxyTrustVerifier depends on this baseline as a bootstrap, but ultimately asks the server if it trusts the proxy.

The client constraints are excluded from the trust verification of a proxy because it is assumed that the caller will subsequently either replace them with its own constraints that are known to be trusted, or has independently decided to trust the existing client constraints.

Note that trust verification does not prevent denial-of-service attacks. If a proxy that uses untrusted code is unmarshalled, the untrusted code can execute before trust verification takes place. In deployments where the trusted sources of downloaded code are known in advance, the RequireDlPermProvider can be used to prevent code downloading from untrusted sources.

Dynamic Permission Grants

Once a client decides that it trusts a proxy, it may need to grant additional permissions (such as AuthenticationPermission) to that proxy, so that subsequent calls to the proxy operate correctly. It is important to delay granting such permissions until after the trust decision, so that an untrusted proxy cannot abuse the grants in a way that might cause harm.

Dynamic grants require support from the Policy provider. The net.jini.security.policy package provides a standard interface for security policy providers capable of dynamic permission grants, as well as a set of composable security policy providers supporting dynamic permission grants and aggregation of multiple security policies in a single virtual machine.

Security.grantSupported can be used to determine if the installed security policy supports dynamic grants, and Security.grant can be used to make dynamic permission grants. The typical use is to grant permissions to the class loader of the proxy object's top-level class, coupled with the principals of the currently executing subject:

SomeService proxy = ...;
Permission[] grants = ...;
Security.grant(proxy.getClass(), grants);
In order to dynamically grant a permission, the client itself must have the corresponding GrantPermission. Because the dynamic grant is coupled with the current subject, proxy code must assume that actions executed using AccessController.doPrivileged will not have the granted permissions (because that method executes the action with no subject); Security.doPrivileged should be used instead to maintain the current subject and thereby enable privileges in a way that retains the granted permissions.

Code Integrity

As described in the Integrity constraint class, for a remote call to have integrity, both code and data must have integrity, and a common technique is to use codebase URLs that provide content integrity. Rather than mandating which URLs provide content integrity, a pluggable framework is provided, and Security.verifyCodebaseIntegrity can be used to determine if all of the URLs in a codebase provide content integrity, based on whatever IntegrityVerifier instances have been configured. Application code normally does not call this method directly; rather, it is called by the input streams (such as MarshalInputStream) used to unmarshal objects during a remote call. The HttpmdIntegrityVerifier, HttpsIntegrityVerifier, and FileIntegrityVerifier classes are provided to verify the integrity of HTTPMD, HTTPS, and FILE URLs, respectively.
Since:
2.0
Version:
2.0