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);
}