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 package java.security;
19 
20 import java.nio.ByteBuffer;
21 import 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  */
28 public 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      */
SecureClassLoader()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      */
SecureClassLoader(ClassLoader parent)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      */
getPermissions(CodeSource codesource)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      */
defineClass(String name, byte[] b, int off, int len, CodeSource cs)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      */
defineClass(String name, ByteBuffer b, CodeSource cs)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
getPD(CodeSource cs)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