ProtectionDomain.java revision adc854b798c1cfe3bfd4c27d68d5cee38ca617da
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
18/**
19* @author Alexander V. Astapchuk
20* @version $Revision$
21*/
22
23package java.security;
24
25/**
26 * {@code ProtectionDomain} represents all permissions that are granted to a
27 * specific code source. The {@link ClassLoader} associates each class with the
28 * corresponding {@code ProtectionDomain}, depending on the location and the
29 * certificates (encapsulates in {@link CodeSource}) it loads the code from.
30 * <p>
31 * A class belongs to exactly one protection domain and the protection domain
32 * can not be changed during the lifetime of the class.
33 * </p>
34 *
35 * @since Android 1.0
36 */
37public class ProtectionDomain {
38
39    // CodeSource for this ProtectionDomain
40    private CodeSource codeSource;
41
42    // Static permissions for this ProtectionDomain
43    private PermissionCollection permissions;
44
45    // ClassLoader
46    private ClassLoader classLoader;
47
48    // Set of principals associated with this ProtectionDomain
49    private Principal[] principals;
50
51    // false if this ProtectionDomain was constructed with static
52    // permissions, true otherwise.
53    private boolean dynamicPerms;
54
55    /**
56     * Constructs a new instance of {@code ProtectionDomain} with the specified
57     * code source and the specified static permissions.
58     * <p>
59     * If {@code permissions} is not {@code null}, the {@code permissions}
60     * collection is made immutable by calling
61     * {@link PermissionCollection#setReadOnly()} and it is considered as
62     * granted statically to this {@code ProtectionDomain}.
63     * </p>
64     * <p>
65     * The policy will not be consulted by access checks against this {@code
66     * ProtectionDomain}.
67     * </p>
68     * <p>
69     * If {@code permissions} is {@code null}, the method
70     * {@link ProtectionDomain#implies(Permission)} always returns {@code false}
71     * .
72     * </p>
73     *
74     * @param cs
75     *            the code source associated with this domain, maybe {@code
76     *            null}.
77     * @param permissions
78     *            the {@code PermissionCollection} containing all permissions to
79     *            be statically granted to this {@code ProtectionDomain}, maybe
80     *            {@code null}.
81     * @since Android 1.0
82     */
83    public ProtectionDomain(CodeSource cs, PermissionCollection permissions) {
84        this.codeSource = cs;
85        if (permissions != null) {
86            permissions.setReadOnly();
87        }
88        this.permissions = permissions;
89        //this.classLoader = null;
90        //this.principals = null;
91        //dynamicPerms = false;
92    }
93
94
95    /**
96     * Constructs a new instance of {@code ProtectionDomain} with the specified
97     * code source, the permissions, the class loader and the principals.
98     * <p>
99     * If {@code permissions} is {@code null}, and access checks are performed
100     * against this protection domain, the permissions defined by the policy are
101     * consulted. If {@code permissions} is not {@code null}, the {@code
102     * permissions} collection is made immutable by calling
103     * {@link PermissionCollection#setReadOnly()}. If access checks are
104     * performed, the policy and the provided permission collection are checked.
105     * </p>
106     * <p>
107     * External modifications of the provided {@code principals} array has no
108     * impact on this {@code ProtectionDomain}.
109     * </p>
110     *
111     * @param cs
112     *            the code source associated with this domain, maybe {@code
113     *            null}.
114     * @param permissions
115     *            the permissions associated with this domain, maybe {@code
116     *            null}.
117     * @param cl
118     *            the class loader associated with this domain, maybe {@code
119     *            null}.
120     * @param principals
121     *            the principals associated with this domain, maybe {@code null}
122     *            .
123     * @since Android 1.0
124     */
125    public ProtectionDomain(CodeSource cs, PermissionCollection permissions,
126            ClassLoader cl, Principal[] principals) {
127        this.codeSource = cs;
128        if (permissions != null) {
129            permissions.setReadOnly();
130        }
131        this.permissions = permissions;
132        this.classLoader = cl;
133        if (principals != null) {
134            this.principals = new Principal[principals.length];
135            System.arraycopy(principals, 0, this.principals, 0,
136                    this.principals.length);
137        }
138        dynamicPerms = true;
139    }
140
141    /**
142     * Returns the {@code ClassLoader} associated with this {@code
143     * ProtectionDomain}.
144     *
145     * @return the {@code ClassLoader} associated with this {@code
146     *         ProtectionDomain}, maybe {@code null}.
147     * @since Android 1.0
148     */
149    public final ClassLoader getClassLoader() {
150        return classLoader;
151    }
152
153    /**
154     * Returns the {@code CodeSource} of this {@code ProtectionDomain}.
155     *
156     * @return the {@code CodeSource} of this {@code ProtectionDomain}, maybe
157     *         {@code null}.
158     * @since Android 1.0
159     */
160    public final CodeSource getCodeSource() {
161        return codeSource;
162    }
163
164    /**
165     * Returns the static permissions that are granted to this {@code
166     * ProtectionDomain}.
167     *
168     * @return the static permissions that are granted to this {@code
169     *         ProtectionDomain}, maybe {@code null}.
170     * @since Android 1.0
171     */
172    public final PermissionCollection getPermissions() {
173        return permissions;
174    }
175
176    /**
177     * Returns the principals associated with this {@code ProtectionDomain}.
178     * Modifications of the returned {@code Principal} array has no impact on
179     * this {@code ProtectionDomain}.
180     *
181     * @return the principals associated with this {@code ProtectionDomain}.
182     * @since Android 1.0
183     */
184    public final Principal[] getPrincipals() {
185        if( principals == null ) {
186            return new Principal[0];
187        }
188        Principal[] tmp = new Principal[principals.length];
189        System.arraycopy(principals, 0, tmp, 0, tmp.length);
190        return tmp;
191    }
192
193    /**
194     * Indicates whether the specified permission is implied by this {@code
195     * ProtectionDomain}.
196     * <p>
197     * If this {@code ProtectionDomain} was constructed with
198     * {@link #ProtectionDomain(CodeSource, PermissionCollection)}, the
199     * specified permission is only checked against the permission collection
200     * provided in the constructor. If {@code null} was provided, {@code false}
201     * is returned.
202     * </p>
203     * <p>
204     * If this {@code ProtectionDomain} was constructed with
205     * {@link #ProtectionDomain(CodeSource, PermissionCollection, ClassLoader, Principal[])}
206     * , the specified permission is checked against the policy and the
207     * permission collection provided in the constructor.
208     * </p>
209     *
210     * @param permission
211     *            the permission to check against the domain.
212     * @return {@code true} if the specified {@code permission} is implied by
213     *         this {@code ProtectionDomain}, {@code false} otherwise.
214     * @since Android 1.0
215     */
216    public boolean implies(Permission permission) {
217        // First, test with the Policy, as the default Policy.implies()
218        // checks for both dynamic and static collections of the
219        // ProtectionDomain passed...
220        if (dynamicPerms
221                && Policy.getAccessiblePolicy().implies(this, permission)) {
222            return true;
223        }
224
225        // ... and we get here if
226        // either the permissions are static
227        // or Policy.implies() did not check for static permissions
228        // or the permission is not implied
229        return permissions == null ? false : permissions.implies(permission);
230    }
231
232    /**
233     * Returns a string containing a concise, human-readable description of the
234     * this {@code ProtectionDomain}.
235     *
236     * @return a printable representation for this {@code ProtectionDomain}.
237     * @since Android 1.0
238     */
239    public String toString() {
240        //FIXME: 1.5 use StreamBuilder here
241        StringBuffer buf = new StringBuffer(200);
242        buf.append("ProtectionDomain\n"); //$NON-NLS-1$
243        buf.append("CodeSource=").append( //$NON-NLS-1$
244                codeSource == null ? "<null>" : codeSource.toString()).append( //$NON-NLS-1$
245                "\n"); //$NON-NLS-1$
246        buf.append("ClassLoader=").append( //$NON-NLS-1$
247                classLoader == null ? "<null>" : classLoader.toString()) //$NON-NLS-1$
248                .append("\n"); //$NON-NLS-1$
249        if (principals == null || principals.length == 0) {
250            buf.append("<no principals>\n"); //$NON-NLS-1$
251        } else {
252            buf.append("Principals: <\n"); //$NON-NLS-1$
253            for (int i = 0; i < principals.length; i++) {
254                buf.append("\t").append( //$NON-NLS-1$
255                        principals[i] == null ? "<null>" : principals[i] //$NON-NLS-1$
256                                .toString()).append("\n"); //$NON-NLS-1$
257            }
258            buf.append(">"); //$NON-NLS-1$
259        }
260
261        //permissions here
262        buf.append("Permissions:\n"); //$NON-NLS-1$
263        if (permissions == null) {
264            buf.append("\t\t<no static permissions>\n"); //$NON-NLS-1$
265        } else {
266            buf.append("\t\tstatic: ").append(permissions.toString()).append( //$NON-NLS-1$
267                    "\n"); //$NON-NLS-1$
268        }
269
270        if (dynamicPerms) {
271            if (Policy.isSet()) {
272                PermissionCollection perms;
273                perms = Policy.getAccessiblePolicy().getPermissions(this);
274                if (perms == null) {
275                    buf.append("\t\t<no dynamic permissions>\n"); //$NON-NLS-1$
276                } else {
277                    buf.append("\t\tdynamic: ").append(perms.toString()) //$NON-NLS-1$
278                            .append("\n"); //$NON-NLS-1$
279                }
280            } else {
281                buf.append("\t\t<no dynamic permissions>\n"); //$NON-NLS-1$
282            }
283        }
284        return buf.toString();
285    }
286}
287