DefaultPolicypublic class DefaultPolicy extends Policy Default Policy implementation based on policy configuration files. This
implementation recognizes text files, consisting of clauses with the
following syntax:
keystore "some_keystore_url" [, "keystore_type"];
grant [SignedBy "signer_names"] [, CodeBase "URL"]
[, Principal [principal_class_name] "principal_name"]
[, Principal [principal_class_name] "principal_name"] ... {
permission permission_class_name [ "target_name" ] [, "action"]
[, SignedBy "signer_names"];
permission ...
};
The keystore clause specifies reference to a keystore, which is a
database of private keys and their associated digital certificates. The
keystore is used to look up the certificates of signers specified in the
grant entries of the file. The policy file can contain any number of
keystore entries which can appear at any ordinal position. However,
only the first successfully loaded keystore is used, others are ignored. The
keystore must be specified if some grant clause refers to a certificate's
alias.
The grant clause associates a CodeSource (consisting of an URL and a
set of certificates) of some executable code with a set of Permissions which
should be granted to the code. So, the CodeSource is defined by values of
CodeBase and SignedBy fields. The CodeBase value must
be in URL format, while SignedBy value is a (comma-separated list of)
alias(es) to keystore certificates. These fields can be omitted to denote any
codebase and any signers (including case of unsigned code), respectively.
Also, the code may be required to be executed on behalf of some Principals
(in other words, code's ProtectionDomain must have the array of Principals
associated) in order to possess the Permissions. This fact is indicated by
specifying one or more Principal fields in the grant clause.
Each Principal is specified as class/name pair; name and class can be either
concrete value or wildcard * . As a special case, the class value may
be omitted and then the name is treated as an alias to X.509 Certificate, and
the Principal is assumed to be javax.security.auth.x500.X500Principal with a
name of subject's distinguished name from the certificate.
The order between the CodeBase , SignedBy , and Principal
fields does not matter. The policy file can contain any number of grant
clauses.
Each grant clause must contain one or more permission entry.
The permission entry consist of a fully qualified class name along with
optional name , actions and signedby values. Name and
actions are arguments to the corresponding constructor of the permission
class. SignedBy value represents the keystore alias(es) to certificate(s)
used to sign the permission class. That is, this permission entry is
effective (i.e., access control permission will be granted based on this
entry) only if the bytecode implementation of permission class is verified to
be correctly signed by the said alias(es).
The policy content may be parameterized via property expansion. Namely,
expressions like ${key} are replaced by values of corresponding
system properties. Also, the special slash key (i.e. ${/}) is
supported, it is a shortcut to "file.separator" key. Property
expansion is performed anywhere a double quoted string is allowed in the
policy file. However, this feature is controlled by security properties and
should be turned on by setting "policy.expandProperties" property
to true .
If property expansion fails (due to a missing key), a corresponding entry is
ignored. For fields of keystore and grant clauses, the whole
clause is ignored, and for permission entry, only that entry is
ignored.
The policy also supports generalized expansion in permissions names, of
expressions like ${{protocol:data}} . Currently the following
protocols supported:
- self
- Denotes substitution to a principal information of the parental Grant
entry. Replaced by a space-separated list of resolved Principals (including
wildcarded), each formatted as class "name" . If parental
Grant entry has no Principals, the permission is ignored.
- alias: name
- Denotes substitution of a KeyStore alias. Namely, if a KeyStore has an
X.509 certificate associated with the specified name, then replaced by
javax.security.auth.x500.X500Principal " DN "
string, where DN is a certificate's subject distinguished name.
This implementation is thread-safe. The policy caches sets of calculated
permissions for the requested objects (ProtectionDomains and CodeSources) via
WeakHashMap; the cache is cleaned either explicitly during refresh()
invocation, or naturally by garbage-collecting the corresponding objects. |
Fields Summary |
---|
public static final String | JAVA_SECURITY_POLICYSystem property for dynamically added policy location. | public static final String | POLICY_URL_PREFIXPrefix for numbered Policy locations specified in security.properties. | private final Set | grants | private final Map | cache | private final DefaultPolicyParser | parser | private boolean | initiailized |
Constructors Summary |
---|
public DefaultPolicy()Default constructor, equivalent to
DefaultPolicy(new DefaultPolicyParser()) .
this(new DefaultPolicyParser());
| public DefaultPolicy(DefaultPolicyParser dpr)Extension constructor for plugging-in a custom parser. Defers policy data
initialization before the first getPermissions() call
(though policy may be refreshed explicitly, as well).
parser = dpr;
initiailized = false;
refresh();
|
Methods Summary |
---|
public java.security.PermissionCollection | getPermissions(java.security.ProtectionDomain pd)Returns collection of permissions allowed for the domain
according to the policy. The evaluated characteristics of the
domain are it's codesource and principals; they are assumed
to be null if the domain is null .
if (!initiailized) {
synchronized (this) {
if (!initiailized) {
refresh();
}
}
}
Collection<Permission> pc = cache.get(pd);
if (pc == null) {
//have to synchronize to exclude cache pollution after refresh
synchronized (cache) {
// double check in case value has been put to cache
// while we've been awaiting monitor
pc = cache.get(pd);
if (pc == null) {
pc = new HashSet<Permission>();
Iterator<PolicyEntry> it = grants.iterator();
while (it.hasNext()) {
PolicyEntry ge = (PolicyEntry)it.next();
if (ge.impliesPrincipals(pd == null ? null : pd.getPrincipals())
&& ge.impliesCodeSource(pd == null ? null : pd.getCodeSource())) {
pc.addAll(ge.getPermissions());
}
}
cache.put(pd, pc);
}
}
}
return PolicyUtils.toPermissionCollection(pc);
| public java.security.PermissionCollection | getPermissions(java.security.CodeSource cs)Returns collection of permissions allowed for the codesource
according to the policy.
The evaluation assumes that current principals are undefined.
if (!initiailized) {
synchronized (this) {
if (!initiailized) {
refresh();
}
}
}
Collection<Permission> pc = cache.get(cs);
if (pc == null) {
//have to synchronize to exclude cache pollution after refresh
synchronized (cache) {
// double check in case value has been put to cache
// while we've been awaiting monitor
pc = cache.get(cs);
if (pc == null) {
pc = new HashSet<Permission>();
Iterator<PolicyEntry> it = grants.iterator();
while (it.hasNext()) {
PolicyEntry ge = (PolicyEntry)it.next();
if (ge.impliesPrincipals(null)
&& ge.impliesCodeSource(cs)) {
pc.addAll(ge.getPermissions());
}
}
cache.put(cs, pc);
}
}
}
return PolicyUtils.toPermissionCollection(pc);
| public synchronized void | refresh()Gets fresh list of locations and tries to load all of them in sequence;
failed loads are ignored. After processing all locations, old policy
settings are discarded and new ones come into force.
This method is declared synchronized to avoid concurrent reloading.
Set<PolicyEntry> fresh = new HashSet<PolicyEntry>();
Properties system = new Properties(AccessController
.doPrivileged(new PolicyUtils.SystemKit()));
system.setProperty("/", File.separator); //$NON-NLS-1$
URL[] policyLocations = PolicyUtils.getPolicyURLs(system,
JAVA_SECURITY_POLICY,
POLICY_URL_PREFIX);
for (int i = 0; i < policyLocations.length; i++) {
try {
//TODO debug log
//System.err.println("Parsing policy file: " + policyLocations[i]);
fresh.addAll(parser.parse(policyLocations[i], system));
} catch (Exception e) {
// TODO log warning
//System.err.println("Ignoring policy file: "
// + policyLocations[i] + ". Reason:\n"+ e);
}
}
// XXX: what if new policy is empty - provide some default??
// we could safely replace references instead of
// synchronizing access:
// <pre>
// grants = fresh;
// cache = new WeakHashMap();
// </pre>
// but there is possibility that concurrent thread will put
// old data to cache right after we finish refresh(),
// thus synchronization is added in getPermissions() methods...
synchronized (cache) {
grants.clear();
grants.addAll(fresh);
cache.clear();
}
initiailized = true;
|
|