Deployed nodes will still require some policy file configuration, for a secure configuration, this is how deployment should work:

  1. The node will need to be configured to authenticate itself an
     administrator and a registrar.
  2. Using secure discovery v2, the node discovers a ServiceRegistrar,
     which is authenticated before code is downloaded.
  3. The node then registers a RemotePolicy with the registrar and
     awaits policy configuration by an authenticating administration
     client (the local RemotePolicy service must also be authenticated
     by the client).
  4. The RemotePolicy service receives PermissionGrant's that define
     the CodeSource Certificates required for DownloadPermission, this
     prevents any unauthorised code from executing unmarshalling dos
     attacks.  It also receives grants for user Principals and
     CodeSource Certificate combinations.  This could be a djinn where
     different company's (represented by groups, each responsible for
     it's own registrar) systems interact, so different permissions
     based on code signers from various companies and user principals
     will determine the level of access at each node.
  5. The node should now be ready to register any other services
     provided with additional registrars and allow user access.
  6. The node is free to look up services provided by other registrars
     and join other groups.
  7. If all endpoints used are secure and authentication is required
     and proxy verification is used, we have a relatively secure djinn.
  8. Actual Service API will be determined and agreed upon by the
     cooperating entities, which may be added to registrars and systems
     at any time.

DownloadPermission is a misnomer, it should be called a ClassLoadPermission, because it doesn't guard against download, only class loading. It may also be possible to restrict loading and related dos attacks with ServiceUI, by requiring DownloadPermission by default for all remote code.

Having introduced RemotePolicy earlier, you're probably wondering what PermissionGrant is? (Please see earlier post for RemotePolicy details).

public interface RemotePolicy {
public void replace(PermissionGrant[] policyPermissions) throws IOException;
}

PermissionGrant is an interface (appended), implementations of it contain Permissions. The policy asks the PermissionGrant if it implies a ProtectionDomain, during a permission check, if it does, the Permissions granted by the PermissionGrant are added to the cache for that ProtectionDomain, this includes any ProtectionDomains created by SubjectDomainCombiner.

PermissionGrant's may be created by parsing java policy files with PolicyParser, by using a PermissionGrantBuilder, or by asking an existing PermissionGrant for a PermissionGrantBuilder.

PermissionGrantBuilder is an abstract class, with a static factory method create(), that returns an implementation of PermissionGrantBuilder. At this stage the implementation cannot be changed by configuration, but that may change in future.

PermissionGrant implementations (there are currently 5) are Serializable, yet immutable with all fields final. Instead of serializing their internal state, they serialize a PermissionGrantBuilder, which has a readResolve method that calls build(), creating a new immutable PermissionGrant object at the remote end.

No implementation details are published publicly, no public constructors, not even serialized state. To the client developer, there is only a single type of PermissionGrant, which can be obtained via a builder or a policy file parser. For release evolution, if deployed nodes end up with different versions of builders, with new types of PermissionGrant's, the builder will select the most appropriate implementation upon deserialization. The implementation is flexible for release evolution.

This is important to keep life simple for the application developer, the builder selects the most appropriate implementation, based on the methods called, so the developer doesn't need to investigate all the implementations to figure out which is most applicable.

Further, because the policy resides in the extension class loader (jre/lib/ext/), the PermissionGrant interface and abstract class PermissionGrantBuilder must too, but the implementations (which the policy can't see) don't need to.

The new Concurrent DynamicPolicy implementation also uses PermissionGrant internally (via the builder) to create dynamic grant's, the dyanamic grants are still called using the existing method in DynamicPolicy, but it reduces the need for additional implementation private classes in the policy for the grants, making the policy easier to understand and read.

There is one last complication, because the Policy doesn't know the implementation of PermissionGrant, it can't trust it's immutibility, for security purposes, it must extract all permissions and check the current call stack has the permission to grant them, if so the policy stores the permissions in a ConcurrentMap for later retrieval, it never again asks the PermissionGrant for the permission's it contains, it only asks if it implies(ProtectionDomain), or if it isVoid(). Eg: A PermissionGrant becomes void if it has been granted to a ClassLoader, which becomes later garbage collected.

PermissionGrant's are not intended to be remote objects.

In case you noticed, Exclusion is for convenience, to exclude one or more CodeSource or URL's (eg a third party library you've signed and deployed) from receiving a blanket grant, applied to Subject Principals and jar files signed by your Certificate's.

It's often the case that third party libraries have more functionality than you need, you may not have access to source code to fix vulnerabilities, so not granting Permission's that you don't require (by exclusion) in a grant you've made to all ProtectionDomains, that contain Subject Principals and CodeSource's signed with your Certificates, which an attacker could use where a vulnerability exists is common sense. When you sign and deploy these libraries along with your code, it saves you from having to sign them with a different signer certificate.

Exclusions are not supported by standard java policy files.

/**
* PermissionGrant's are expected to be effectively immutable,
* threadsafe and have a good hashCode implementation to perform well in
* Collections.
*
* You shouldn't pass around PermissionGrant's to just anyone as they can
* provide an attacker with information about which Permission's may be granted.
*
* @author Peter Firmstone
*/
public interface PermissionGrant {

   /**
* A DynamicPolicy implementation can use a PermissionGrant as a container
    * for Dynamic Grant's.  A PermissionGrant is first asked by the Policy
* if it applies to a Particular ProtectionDomain, if it does, the Policy
    * calls getPermissions.
    *
    * Dynamic grants can be denied to some ProtectionDomains based on
* CodeSource or URL's for codebases, this is to remove the possiblity of
    * executing Permissions for vulnerable codebases, once a vulnerability
    * is identified after the fact.
    *
    * @param pd ProtectionDomain
    * @return
    * @see RevokeableDynamicPolicy
    */
   boolean implies(ProtectionDomain pd);

   /**
    * Checks if this PermissionGrant applies to the passed in ClassLoader
    * and Principal's.
    *
    * Note that if this method returns false, it doesn't necessarily mean
* that the grant will not apply to the ClassLoader, since it will depend on
    * the contents of the ClassLoader and that is indeterminate. It just
    * indicates that the grant definitely does apply if it returns true.
    *
* If this method returns false, follow up using the ProtectionDomain for a
    * more specific test, which may return true.
    */
   boolean implies(ClassLoader cl, Principal[] pal);

   /**
    * Checks if this PermissionGrant applies to the passed in CodeSource
    * and Principal's.
    * @param cs
    * @return
    */
   boolean implies(CodeSource codeSource, Principal[] pal);

   @Override
   boolean equals(Object o);

   /**
    * Returns an unmodifiable Collection of permissions defined by this
    * PermissionGrant, which may be empty, but not null.
    * @return
    */
   Collection<Permission> getPermissions();

   @Override
   int hashCode();

   /**
    * Returns true if this PermissionGrant defines no Permissions, or if
* a PermissionGrant was made to a ProtectionDomain that no longer exists,
    * or if the Exclusion excludes the PermissionGrant.
    */
   public boolean isVoid(Exclusion excl);

}

Reply via email to