blob: bca7207a69dd9a4a1fc5179777c1027e9db86e9e [file] [log] [blame]
/*
* 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.nio.ByteBuffer;
import java.util.HashMap;
/**
* {@code SecureClassLoader} represents a {@code ClassLoader} which associates
* the classes it loads with a code source and provide mechanisms to allow the
* relevant permissions to be retrieved.
*/
public class SecureClassLoader extends ClassLoader {
// A cache of ProtectionDomains for a given CodeSource
private HashMap<CodeSource, ProtectionDomain> pds = new HashMap<CodeSource, ProtectionDomain>();
/**
* Constructs a new instance of {@code SecureClassLoader}. The default
* parent {@code ClassLoader} is used.
* <p>
* If a {@code SecurityManager} is installed, code calling this constructor
* needs the {@code SecurityPermission} {@code checkCreateClassLoader} to be
* granted, otherwise a {@code SecurityException} will be thrown.
*
* @throws SecurityException
* if a {@code SecurityManager} is installed and the caller does
* not have permission to invoke this constructor.
*/
protected SecureClassLoader() {
super();
}
/**
* Constructs a new instance of {@code SecureClassLoader} with the specified
* parent {@code ClassLoader}.
* <p>
* If a {@code SecurityManager} is installed, code calling this constructor
* needs the {@code SecurityPermission} {@code checkCreateClassLoader} to be
* granted, otherwise a {@code SecurityException} will be thrown.
*
* @param parent
* the parent {@code ClassLoader}.
* @throws SecurityException
* if a {@code SecurityManager} is installed and the caller does
* not have permission to invoke this constructor.
*/
protected SecureClassLoader(ClassLoader parent) {
super(parent);
}
/**
* Returns the {@code PermissionCollection} for the specified {@code
* CodeSource}.
*
* @param codesource
* the code source.
* @return the {@code PermissionCollection} for the specified {@code
* CodeSource}.
*/
protected PermissionCollection getPermissions(CodeSource codesource) {
// Do nothing by default, ProtectionDomain will take care about
// permissions in dynamic
return new Permissions();
}
/**
* Constructs a new class from an array of bytes containing a class
* definition in class file format with an optional {@code CodeSource}.
*
* @param name
* the name of the new class.
* @param b
* a memory image of a class file.
* @param off
* the start offset in b of the class data.
* @param len
* the length of the class data.
* @param cs
* the {@code CodeSource}, or {@code null}.
* @return a new class.
* @throws IndexOutOfBoundsException
* if {@code off} or {@code len} are not valid in respect to
* {@code b}.
* @throws ClassFormatError
* if the specified data is not valid class data.
* @throws SecurityException
* if the package to which this class is to be added, already
* contains classes which were signed by different certificates,
* or if the class name begins with "java."
*/
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
CodeSource cs) {
return cs == null ? defineClass(name, b, off, len) : defineClass(name,
b, off, len, getPD(cs));
}
/**
* Constructs a new class from an array of bytes containing a class
* definition in class file format with an optional {@code CodeSource}.
*
* @param name
* the name of the new class.
* @param b
* a memory image of a class file.
* @param cs
* the {@code CodeSource}, or {@code null}.
* @return a new class.
* @throws ClassFormatError
* if the specified data is not valid class data.
* @throws SecurityException
* if the package to which this class is to be added, already
* contains classes which were signed by different certificates,
* or if the class name begins with "java."
*/
protected final Class<?> defineClass(String name, ByteBuffer b, CodeSource cs) {
//FIXME 1.5 - remove b.array(), call super.defineClass(,ByteBuffer,)
// directly
byte[] data = b.array();
return cs == null ? defineClass(name, data, 0, data.length)
: defineClass(name, data, 0, data.length, getPD(cs));
}
// Constructs and caches ProtectionDomain for the given CodeSource
// object.<br>
// It calls {@link getPermissions()} to get a set of permissions.
//
// @param cs CodeSource object
// @return ProtectionDomain for the passed CodeSource object
private ProtectionDomain getPD(CodeSource cs) {
if (cs == null) {
return null;
}
// need to cache PDs, otherwise every class from a given CodeSource
// will have it's own ProtectionDomain, which does not look right.
ProtectionDomain pd;
synchronized (pds) {
if ((pd = pds.get(cs)) != null) {
return pd;
}
PermissionCollection perms = getPermissions(cs);
pd = new ProtectionDomain(cs, perms, this, null);
pds.put(cs, pd);
}
return pd;
}
}