1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security;
19
20import java.util.Enumeration;
21
22import org.apache.harmony.security.fortress.DefaultPolicy;
23import org.apache.harmony.security.fortress.PolicyUtils;
24
25
26/**
27 * {@code Policy} is the common super type of classes which represent a system
28 * security policy. The {@code Policy} specifies which permissions apply to
29 * which code sources.
30 * <p>
31 * The system policy can be changed by setting the {@code 'policy.provider'}
32 * property in the file named {@code JAVA_HOME/lib/security/java.security} to
33 * the fully qualified class name of the desired {@code Policy}.
34 * <p>
35 * Only one instance of a {@code Policy} is active at any time.
36 */
37public abstract class Policy {
38
39    // Key to security properties, defining default policy provider.
40    private static final String POLICY_PROVIDER = "policy.provider"; //$NON-NLS-1$
41
42    // The SecurityPermission required to set custom Policy.
43    private static final SecurityPermission SET_POLICY = new SecurityPermission(
44            "setPolicy"); //$NON-NLS-1$
45
46    // The SecurityPermission required to get current Policy.
47    private static final SecurityPermission GET_POLICY = new SecurityPermission(
48            "getPolicy"); //$NON-NLS-1$
49
50    // The policy currently in effect.
51    private static Policy activePolicy;
52
53    /**
54     * Returns a {@code PermissionCollection} describing what permissions are
55     * allowed for the specified {@code CodeSource} based on the current
56     * security policy.
57     * <p>
58     * Note that this method is not called for classes which are in the system
59     * domain (i.e. system classes). System classes are always given
60     * full permissions (i.e. AllPermission). This can not be changed by
61     * installing a new policy.
62     *
63     * @param cs
64     *            the {@code CodeSource} to compute the permissions for.
65     * @return the permissions that are granted to the specified {@code
66     *         CodeSource}.
67     */
68    public abstract PermissionCollection getPermissions(CodeSource cs);
69
70    /**
71     * Reloads the policy configuration for this {@code Policy} instance.
72     */
73    public abstract void refresh();
74
75    /**
76     * Returns a {@code PermissionCollection} describing what permissions are
77     * allowed for the specified {@code ProtectionDomain} (more specifically,
78     * its {@code CodeSource}) based on the current security policy.
79     * <p>
80     * Note that this method is not< called for classes which are in the
81     * system domain (i.e. system classes). System classes are always
82     * given full permissions (i.e. AllPermission). This can not be changed by
83     * installing a new policy.
84     *
85     * @param domain
86     *            the {@code ProtectionDomain} to compute the permissions for.
87     * @return the permissions that are granted to the specified {@code
88     *         CodeSource}.
89     */
90    public PermissionCollection getPermissions(ProtectionDomain domain) {
91        if (domain != null) {
92            return getPermissions(domain.getCodeSource());
93        }
94        return new Permissions();
95    }
96
97    /**
98     * Indicates whether the specified {@code Permission} is implied by the
99     * {@code PermissionCollection} of the specified {@code ProtectionDomain}.
100     *
101     * @param domain
102     *            the {@code ProtectionDomain} for which the permission should
103     *            be granted.
104     * @param permission
105     *            the {@code Permission} for which authorization is to be
106     *            verified.
107     * @return {@code true} if the {@code Permission} is implied by the {@code
108     *         ProtectionDomain}, {@code false} otherwise.
109     */
110    public boolean implies(ProtectionDomain domain, Permission permission) {
111        if (domain != null) {
112            PermissionCollection total = getPermissions(domain);
113            PermissionCollection inherent = domain.getPermissions();
114            if (total == null) {
115                total = inherent;
116            } else if (inherent != null) {
117                for (Enumeration<Permission> en = inherent.elements(); en.hasMoreElements();) {
118                    total.add(en.nextElement());
119                }
120            }
121            if (total != null && total.implies(permission)) {
122                return true;
123            }
124        }
125        return false;
126    }
127
128    /**
129     * Returns the current system security policy. If no policy has been
130     * instantiated then this is done using the security property {@code
131     * "policy.provider"}.
132     * <p>
133     * If a {@code SecurityManager} is installed, code calling this method needs
134     * the {@code SecurityPermission} {@code getPolicy} to be granted, otherwise
135     * a {@code SecurityException} will be thrown.
136     *
137     * @return the current system security policy.
138     * @throws SecurityException
139     *             if a {@code SecurityManager} is installed and the caller does
140     *             not have permission to invoke this method.
141     */
142    public static Policy getPolicy() {
143        SecurityManager sm = System.getSecurityManager();
144        if (sm != null) {
145            sm.checkPermission(GET_POLICY);
146        }
147        return getAccessiblePolicy();
148    }
149
150     // Reads name of default policy provider from security.properties,
151     // loads the class and instantiates the provider.<br>
152     // In case of any error, including undefined provider name,
153     // returns new instance of org.apache.harmony.security.FilePolicy provider.
154    private static Policy getDefaultProvider() {
155        final String defaultClass = AccessController
156                .doPrivileged(new PolicyUtils.SecurityPropertyAccessor(
157                        POLICY_PROVIDER));
158        if (defaultClass == null) {
159            //TODO log warning
160            //System.err.println("No policy provider specified. Loading the "
161            //           + DefaultPolicy.class.getName());
162            return new DefaultPolicy();
163        }
164
165        // TODO accurate classloading
166        return AccessController.doPrivileged(new PrivilegedAction<Policy>() {
167
168            public Policy run() {
169                try {
170                    return (Policy) Class.forName(defaultClass, true,
171                            ClassLoader.getSystemClassLoader()).newInstance();
172                }
173                catch (Exception e) {
174                    //TODO log error
175                    //System.err.println("Error loading policy provider <"
176                    //                 + defaultClass + "> : " + e
177                    //                 + "\nSwitching to the default "
178                    //                 + DefaultPolicy.class.getName());
179                    return new DefaultPolicy();
180                }
181            }
182        });
183
184    }
185
186    /**
187     * Returns {@code true} if system policy provider is instantiated.
188     */
189    static boolean isSet() {
190        return activePolicy != null;
191    }
192
193    /**
194     * Shortcut accessor for friendly classes, to skip security checks.
195     * If active policy was set to <code>null</code>, loads default provider,
196     * so this method never returns <code>null</code>. <br>
197     * This method is synchronized with setPolicy()
198     */
199    static Policy getAccessiblePolicy() {
200        Policy current = activePolicy;
201        if (current == null) {
202            synchronized (Policy.class) {
203                // double check in case value has been reassigned
204                // while we've been awaiting monitor
205                if (activePolicy == null) {
206                    activePolicy = getDefaultProvider();
207                }
208                return activePolicy;
209            }
210        }
211        return current;
212    }
213
214    /**
215     * Sets the system wide policy.
216     * <p>
217     * If a {@code SecurityManager} is installed, code calling this method needs
218     * the {@code SecurityPermission} {@code setPolicy} to be granted, otherwise
219     * a {@code SecurityException} will be thrown.
220     *
221     * @param policy
222     *            the {@code Policy} to set.
223     * @throws SecurityException
224     *             if a {@code SecurityManager} is installed and the caller does
225     *             not have permission to invoke this method.
226     */
227    public static void setPolicy(Policy policy) {
228        SecurityManager sm = System.getSecurityManager();
229        if (sm != null) {
230            sm.checkPermission(SET_POLICY);
231        }
232        synchronized (Policy.class) {
233            activePolicy = policy;
234        }
235    }
236}
237