| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.security; |
| |
| import java.util.Enumeration; |
| import org.apache.harmony.security.fortress.DefaultPolicy; |
| import org.apache.harmony.security.fortress.Engine; |
| import org.apache.harmony.security.fortress.PolicyUtils; |
| |
| |
| /** |
| * {@code Policy} is the common super type of classes which represent a system |
| * security policy. The {@code Policy} specifies which permissions apply to |
| * which code sources. |
| * <p> |
| * The system policy can be changed by setting the {@code 'policy.provider'} |
| * property in the file named {@code JAVA_HOME/lib/security/java.security} to |
| * the fully qualified class name of the desired {@code Policy}. |
| * <p> |
| * Only one instance of a {@code Policy} is active at any time. |
| */ |
| public abstract class Policy { |
| |
| // Key to security properties, defining default policy provider. |
| private static final String POLICY_PROVIDER = "policy.provider"; |
| |
| // The SecurityPermission required to set custom Policy. |
| private static final SecurityPermission SET_POLICY = new SecurityPermission( |
| "setPolicy"); |
| |
| // The SecurityPermission required to get current Policy. |
| static final SecurityPermission GET_POLICY = new SecurityPermission("getPolicy"); |
| |
| // The policy currently in effect. |
| private static Policy activePolicy; |
| |
| // Store spi implementation service name |
| private static final String POLICYSERVICE = "Policy"; |
| |
| // Used to access common engine functionality |
| private static Engine engine = new Engine(POLICYSERVICE); |
| |
| private String type; |
| |
| private Policy.Parameters params; |
| |
| private Provider provider; |
| |
| // Store used spi implementation |
| private PolicySpi spiImpl; |
| |
| private static final String CREATE_POLICY = "createPolicy."; |
| |
| public Policy() { |
| // default constructor |
| } |
| |
| private Policy(PolicySpi spi, Provider p, String t, Policy.Parameters para) { |
| this.spiImpl = spi; |
| this.provider = p; |
| this.type = t; |
| this.params = para; |
| } |
| |
| private static class PolicyDelegate extends Policy { |
| |
| public PolicyDelegate(PolicySpi spi, Provider p, String t, |
| Policy.Parameters para) { |
| super(spi, p, t, para); |
| } |
| } |
| |
| /** |
| * Answers a Policy object with the specified type and the specified |
| * parameter. |
| * |
| * Traverses the list of registered security providers, beginning with the |
| * most preferred Provider. A new Policy object encapsulating the PolicySpi |
| * implementation from the first Provider that supports the specified type |
| * is returned. |
| * |
| * Note that the list of registered providers may be retrieved via the |
| * Security.getProviders() method. |
| * |
| * @param type - |
| * the specified Policy type. See Appendix A in the Java |
| * Cryptography Architecture API Specification & Reference for a |
| * list of standard Policy types. |
| * @param params - |
| * parameters for the Policy, which may be null. |
| * @return the new Policy object. |
| * @throws NoSuchAlgorithmException - |
| * if no Provider supports a PolicySpi implementation for the |
| * specified type. |
| * @throws SecurityException - |
| * if the caller does not have permission to get a Policy |
| * instance for the specified type. |
| * @throws NullPointerException - |
| * if the specified type is null. |
| * @throws IllegalArgumentException - |
| * if the specified parameters' type are not allowed by the |
| * PolicySpi implementation from the selected Provider. |
| */ |
| public static Policy getInstance(String type, Policy.Parameters params) |
| throws NoSuchAlgorithmException { |
| checkSecurityPermission(new SecurityPermission(CREATE_POLICY + type)); |
| |
| if (type == null) { |
| throw new NullPointerException(); |
| } |
| |
| try { |
| synchronized (engine) { |
| engine.getInstance(type, params); |
| return new PolicyDelegate((PolicySpi) engine.spi, |
| engine.provider, type, params); |
| } |
| |
| } catch (NoSuchAlgorithmException e) { |
| if (e.getCause() == null) { |
| throw e; |
| } |
| throw new IllegalArgumentException("Unrecognized policy parameter: " + params); |
| } |
| } |
| |
| /** |
| * Answers a Policy object of the specified type. |
| * |
| * A new Policy object encapsulating the PolicySpi implementation from the |
| * specified provider is returned. The specified provider must be registered |
| * in the provider list via the Security.getProviders() method, otherwise |
| * NoSuchProviderException will be thrown. |
| * |
| * @param type - |
| * the specified Policy type. So far in Java 6, only 'JavaPolicy' |
| * supported. |
| * @param params - |
| * the Policy.Parameter object, which may be null. |
| * @param provider - |
| * the provider. |
| * @return the new Policy object. |
| * |
| * @throws NoSuchProviderException - |
| * if the specified provider is not registered in the security |
| * provider list. |
| * @throws NoSuchAlgorithmException - |
| * if the specified provider does not support a PolicySpi |
| * implementation for the specified type. |
| * @throws SecurityException - |
| * if the caller does not have permission to get a Policy |
| * instance for the specified type. |
| * @throws NullPointerException - |
| * if the specified type is null. |
| * @throws IllegalArgumentException - |
| * if the specified Provider is null, or if the specified |
| * parameters' type are not allowed by the PolicySpi |
| * implementation from the specified Provider. |
| */ |
| public static Policy getInstance(String type, Policy.Parameters params, |
| String provider) throws NoSuchProviderException, |
| NoSuchAlgorithmException { |
| if ((provider == null) || provider.isEmpty()) { |
| throw new IllegalArgumentException("Provider is null or empty string"); |
| } |
| checkSecurityPermission(new SecurityPermission(CREATE_POLICY + type)); |
| |
| Provider impProvider = Security.getProvider(provider); |
| if (impProvider == null) { |
| throw new NoSuchProviderException("Provider " + provider + " is not available"); |
| } |
| |
| return getInstanceImpl(type, params, impProvider); |
| } |
| |
| /** |
| * Answers a Policy object of the specified type. |
| * |
| * A new Policy object encapsulating the PolicySpi implementation from the |
| * specified Provider object is returned. Note that the specified Provider |
| * object does not have to be registered in the provider list. |
| * |
| * @param type - |
| * the specified Policy type. So far in Java 6, only 'JavaPolicy' |
| * supported. |
| * @param params - |
| * the Policy.Parameter object, which may be null. |
| * @param provider - |
| * the Policy service Provider. |
| * @return the new Policy object. |
| * |
| * @throws NoSuchAlgorithmException - |
| * if the specified Provider does not support a PolicySpi |
| * implementation for the specified type. |
| * @throws IllegalArgumentException - |
| * if the specified Provider is null, or if the specified |
| * parameters' type are not allowed by the PolicySpi |
| * implementation from the specified Provider. |
| * @throws NullPointerException - |
| * if the specified type is null. |
| * @throws SecurityException - |
| * if the caller does not have permission to get a Policy |
| * instance for the specified type. |
| */ |
| public static Policy getInstance(String type, Policy.Parameters params, |
| Provider provider) throws NoSuchAlgorithmException { |
| if (provider == null) { |
| throw new IllegalArgumentException("provider == null"); |
| } |
| checkSecurityPermission(new SecurityPermission(CREATE_POLICY + type)); |
| |
| return getInstanceImpl(type, params, provider); |
| } |
| |
| private static void checkSecurityPermission(SecurityPermission permission) { |
| SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| sm.checkPermission(permission); |
| } |
| } |
| |
| private static Policy getInstanceImpl(String type, Policy.Parameters params, Provider provider) throws NoSuchAlgorithmException { |
| if (type == null) { |
| throw new NullPointerException(); |
| } |
| |
| try { |
| synchronized (engine) { |
| engine.getInstance(type, provider, params); |
| return new PolicyDelegate((PolicySpi) engine.spi, provider, |
| type, params); |
| } |
| } catch (NoSuchAlgorithmException e) { |
| if (e.getCause() == null) { |
| throw e; |
| } |
| throw new IllegalArgumentException("Unrecognized policy parameter: " + params); |
| } |
| } |
| |
| /** |
| * Answers Policy parameters. |
| * |
| * This method will only answer non-null parameters if it was obtained via a |
| * call to Policy.getInstance. Otherwise this method returns null. |
| * |
| * @return Policy parameters, or null. |
| */ |
| public Policy.Parameters getParameters() { |
| return params; |
| } |
| |
| /** |
| * Answers the Provider of this Policy. |
| * |
| * This method will only answer non-null Provider if it was obtained via a |
| * call to Policy.getInstance. Otherwise this method returns null. |
| * |
| * @return the Provider of this Policy, or null. |
| */ |
| public Provider getProvider() { |
| return provider; |
| } |
| |
| /** |
| * Answers the type of this Policy. |
| * |
| * This method will only answer non-null type if it was obtained via a call |
| * to Policy.getInstance. Otherwise this method returns null. |
| * |
| * @return the type of this Policy, or null. |
| */ |
| public String getType() { |
| return type; |
| } |
| |
| /** |
| * A read-only empty PermissionCollection instance. |
| */ |
| public static final PermissionCollection UNSUPPORTED_EMPTY_COLLECTION = new PermissionCollection() { |
| |
| private static final long serialVersionUID = 1L; |
| |
| @Override |
| public void add(Permission permission) { |
| throw new SecurityException( |
| "attempt to add a Permission to a readonly Permissions object"); |
| } |
| |
| @Override |
| public Enumeration<Permission> elements() { |
| return new Permissions().elements(); |
| } |
| |
| @Override |
| public boolean implies(Permission permission) { |
| if (permission == null) { |
| throw new NullPointerException(); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isReadOnly() { |
| // always returns true since it is a read-only instance. |
| // RI does not override this method. |
| return true; |
| } |
| }; |
| |
| /** |
| * A marker interface for Policy parameters. |
| */ |
| public static interface Parameters { |
| // a marker interface |
| } |
| |
| /** |
| * Returns a {@code PermissionCollection} describing what permissions are |
| * allowed for the specified {@code CodeSource} based on the current |
| * security policy. |
| * <p> |
| * Note that this method is not called for classes which are in the system |
| * domain (i.e. system classes). System classes are always given |
| * full permissions (i.e. AllPermission). This can not be changed by |
| * installing a new policy. |
| * |
| * @param cs |
| * the {@code CodeSource} to compute the permissions for. |
| * @return the permissions that are granted to the specified {@code |
| * CodeSource}. |
| */ |
| public PermissionCollection getPermissions(CodeSource cs) { |
| return spiImpl == null ? Policy.UNSUPPORTED_EMPTY_COLLECTION : spiImpl |
| .engineGetPermissions(cs); |
| } |
| |
| /** |
| * Reloads the policy configuration for this {@code Policy} instance. |
| */ |
| public void refresh() { |
| if (spiImpl != null) { |
| spiImpl.engineRefresh(); |
| } |
| } |
| |
| /** |
| * Returns a {@code PermissionCollection} describing what permissions are |
| * allowed for the specified {@code ProtectionDomain} (more specifically, |
| * its {@code CodeSource}) based on the current security policy. |
| * <p> |
| * Note that this method is not< called for classes which are in the |
| * system domain (i.e. system classes). System classes are always |
| * given full permissions (i.e. AllPermission). This can not be changed by |
| * installing a new policy. |
| * |
| * @param domain |
| * the {@code ProtectionDomain} to compute the permissions for. |
| * @return the permissions that are granted to the specified {@code |
| * CodeSource}. |
| */ |
| public PermissionCollection getPermissions(ProtectionDomain domain) { |
| Permissions permissions = new Permissions(); |
| if (domain != null) { |
| try { |
| PermissionCollection cds = getPermissions(domain |
| .getCodeSource()); |
| if (cds != Policy.UNSUPPORTED_EMPTY_COLLECTION) { |
| Enumeration<Permission> elements = cds.elements(); |
| while (elements.hasMoreElements()) { |
| permissions.add(elements.nextElement()); |
| } |
| } |
| } catch (NullPointerException e) { |
| // ignore the exception, just add nothing to the result set |
| } |
| |
| PermissionCollection pds = domain.getPermissions(); |
| if (pds != null) { |
| Enumeration<Permission> pdElements = pds.elements(); |
| while (pdElements.hasMoreElements()) { |
| permissions.add(pdElements.nextElement()); |
| } |
| } |
| } |
| return permissions; |
| } |
| |
| /** |
| * Indicates whether the specified {@code Permission} is implied by the |
| * {@code PermissionCollection} of the specified {@code ProtectionDomain}. |
| * |
| * @param domain |
| * the {@code ProtectionDomain} for which the permission should |
| * be granted. |
| * @param permission |
| * the {@code Permission} for which authorization is to be |
| * verified. |
| * @return {@code true} if the {@code Permission} is implied by the {@code |
| * ProtectionDomain}, {@code false} otherwise. |
| */ |
| public boolean implies(ProtectionDomain domain, Permission permission) { |
| return spiImpl == null ? defaultImplies(domain, permission) : spiImpl |
| .engineImplies(domain, permission); |
| } |
| |
| private boolean defaultImplies(ProtectionDomain domain, Permission permission) { |
| if (domain == null && permission == null) { |
| throw new NullPointerException(); |
| } |
| boolean implies = false; |
| if (domain != null) { |
| PermissionCollection total = getPermissions(domain); |
| PermissionCollection inherent = domain.getPermissions(); |
| if (inherent != null) { |
| Enumeration<Permission> en = inherent.elements(); |
| while (en.hasMoreElements()) { |
| total.add(en.nextElement()); |
| } |
| } |
| try { |
| implies = total.implies(permission); |
| } catch (NullPointerException e) { |
| // return false instead of throwing the NullPointerException |
| implies = false; |
| } |
| } |
| return implies; |
| } |
| |
| /** |
| * Returns the current system security policy. If no policy has been |
| * instantiated then this is done using the security property {@code |
| * "policy.provider"}. |
| * <p> |
| * If a {@code SecurityManager} is installed, code calling this method needs |
| * the {@code SecurityPermission} {@code getPolicy} to be granted, otherwise |
| * a {@code SecurityException} will be thrown. |
| * |
| * @return the current system security policy. |
| * @throws SecurityException |
| * if a {@code SecurityManager} is installed and the caller does |
| * not have permission to invoke this method. |
| */ |
| public static Policy getPolicy() { |
| checkSecurityPermission(GET_POLICY); |
| return getAccessiblePolicy(); |
| } |
| |
| // Reads name of default policy provider from security.properties, |
| // loads the class and instantiates the provider.<br> |
| // In case of any error, including undefined provider name, |
| // returns new instance of org.apache.harmony.security.FilePolicy provider. |
| private static Policy getDefaultProvider() { |
| final String defaultClass = AccessController |
| .doPrivileged(new PolicyUtils.SecurityPropertyAccessor( |
| POLICY_PROVIDER)); |
| if (defaultClass == null) { |
| // TODO log warning |
| // System.err.println("No policy provider specified. Loading the " |
| // + DefaultPolicy.class.getName()); |
| return new DefaultPolicy(); |
| } |
| |
| // TODO accurate classloading |
| return AccessController.doPrivileged(new PrivilegedAction<Policy>() { |
| |
| public Policy run() { |
| try { |
| return (Policy) Class.forName(defaultClass, true, |
| ClassLoader.getSystemClassLoader()).newInstance(); |
| } |
| catch (Exception e) { |
| //TODO log error |
| //System.err.println("Error loading policy provider <" |
| // + defaultClass + "> : " + e |
| // + "\nSwitching to the default " |
| // + DefaultPolicy.class.getName()); |
| return new DefaultPolicy(); |
| } |
| } |
| }); |
| |
| } |
| |
| /** |
| * Returns {@code true} if system policy provider is instantiated. |
| */ |
| static boolean isSet() { |
| return activePolicy != null; |
| } |
| |
| /** |
| * Shortcut accessor for friendly classes, to skip security checks. |
| * If active policy was set to <code>null</code>, loads default provider, |
| * so this method never returns <code>null</code>. <br> |
| * This method is synchronized with setPolicy() |
| */ |
| static synchronized Policy getAccessiblePolicy() { |
| if (activePolicy == null) { |
| activePolicy = getDefaultProvider(); |
| } |
| return activePolicy; |
| } |
| |
| /** |
| * Sets the system wide policy. |
| * <p> |
| * If a {@code SecurityManager} is installed, code calling this method needs |
| * the {@code SecurityPermission} {@code setPolicy} to be granted, otherwise |
| * a {@code SecurityException} will be thrown. |
| * |
| * @param policy |
| * the {@code Policy} to set. |
| * @throws SecurityException |
| * if a {@code SecurityManager} is installed and the caller does |
| * not have permission to invoke this method. |
| */ |
| public static void setPolicy(Policy policy) { |
| checkSecurityPermission(SET_POLICY); |
| synchronized (Policy.class) { |
| activePolicy = policy; |
| } |
| } |
| } |