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.nio.ByteBuffer;
21import java.util.HashMap;
22
23/**
24 * {@code SecureClassLoader} represents a {@code ClassLoader} which associates
25 * the classes it loads with a code source and provide mechanisms to allow the
26 * relevant permissions to be retrieved.
27 */
28public class SecureClassLoader extends ClassLoader {
29
30    // A cache of ProtectionDomains for a given CodeSource
31    private HashMap<CodeSource, ProtectionDomain> pds = new HashMap<CodeSource, ProtectionDomain>();
32
33    /**
34     * Constructs a new instance of {@code SecureClassLoader}. The default
35     * parent {@code ClassLoader} is used.
36     */
37    protected SecureClassLoader() {
38    }
39
40    /**
41     * Constructs a new instance of {@code SecureClassLoader} with the specified
42     * parent {@code ClassLoader}.
43     *
44     * @param parent
45     *            the parent {@code ClassLoader}.
46     */
47    protected SecureClassLoader(ClassLoader parent) {
48        super(parent);
49    }
50
51    /**
52     * Returns the {@code PermissionCollection} for the specified {@code
53     * CodeSource}.
54     *
55     * @param codesource
56     *            the code source.
57     * @return the {@code PermissionCollection} for the specified {@code
58     *         CodeSource}.
59     */
60    protected PermissionCollection getPermissions(CodeSource codesource) {
61        // Do nothing by default, ProtectionDomain will take care about
62        // permissions in dynamic
63        return new Permissions();
64    }
65
66    /**
67     * Constructs a new class from an array of bytes containing a class
68     * definition in class file format with an optional {@code CodeSource}.
69     *
70     * @param name
71     *            the name of the new class.
72     * @param b
73     *            a memory image of a class file.
74     * @param off
75     *            the start offset in b of the class data.
76     * @param len
77     *            the length of the class data.
78     * @param cs
79     *            the {@code CodeSource}, or {@code null}.
80     * @return a new class.
81     * @throws IndexOutOfBoundsException
82     *             if {@code off} or {@code len} are not valid in respect to
83     *             {@code b}.
84     * @throws ClassFormatError
85     *             if the specified data is not valid class data.
86     * @throws SecurityException
87     *             if the package to which this class is to be added, already
88     *             contains classes which were signed by different certificates,
89     *             or if the class name begins with "java."
90     */
91    protected final Class<?> defineClass(String name, byte[] b, int off, int len,
92            CodeSource cs) {
93        return cs == null ? defineClass(name, b, off, len) : defineClass(name,
94                b, off, len, getPD(cs));
95    }
96
97    /**
98     * Constructs a new class from an array of bytes containing a class
99     * definition in class file format with an optional {@code CodeSource}.
100     *
101     * @param name
102     *            the name of the new class.
103     * @param b
104     *            a memory image of a class file.
105     * @param cs
106     *            the {@code CodeSource}, or {@code null}.
107     * @return a new class.
108     * @throws ClassFormatError
109     *             if the specified data is not valid class data.
110     * @throws SecurityException
111     *             if the package to which this class is to be added, already
112     *             contains classes which were signed by different certificates,
113     *             or if the class name begins with "java."
114     */
115    protected final Class<?> defineClass(String name, ByteBuffer b, CodeSource cs) {
116        //FIXME 1.5 - remove b.array(), call super.defineClass(,ByteBuffer,)
117        // directly
118        byte[] data = b.array();
119        return cs == null ? defineClass(name, data, 0, data.length)
120                : defineClass(name, data, 0, data.length, getPD(cs));
121    }
122
123    // Constructs and caches ProtectionDomain for the given CodeSource
124    // object.<br>
125    // It calls {@link getPermissions()} to get a set of permissions.
126    //
127    // @param cs CodeSource object
128    // @return ProtectionDomain for the passed CodeSource object
129    private ProtectionDomain getPD(CodeSource cs) {
130        if (cs == null) {
131            return null;
132        }
133        // need to cache PDs, otherwise every class from a given CodeSource
134        // will have it's own ProtectionDomain, which does not look right.
135        ProtectionDomain pd;
136        synchronized (pds) {
137            if ((pd = pds.get(cs)) != null) {
138                return pd;
139            }
140            PermissionCollection perms = getPermissions(cs);
141            pd = new ProtectionDomain(cs, perms, this, null);
142            pds.put(cs, pd);
143        }
144        return pd;
145    }
146}
147