ro.esolutions.licensing.LicenseSecurityManager Maven / Gradle / Ivy
The newest version!
/*
* LicenseSecurityManager.java from LicenseManager modified Monday, June 25, 2012 23:54:40 CDT (-0500).
*
* Copyright 2010-2013 the original author or authors.
*
* Licensed 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 ro.esolutions.licensing;
import java.io.FileDescriptor;
import java.lang.reflect.Member;
import java.net.InetAddress;
import java.security.Permission;
import ro.esolutions.licensing.exception.InsecureEnvironmentException;
/**
* This security manager is one of the most integral pieces to the license manager. It prevents reflection attacks from
* disabling or compromising the security features in this product.
*
* When the security manager is initialized, it first checks if a different security manager is already installed in
* this JVM. If no security manager is installed already, then this security manager installs itself.
*
* If another security manager is already installed, this checks to make sure it prevents reflection attacks against
* critical LicenseManager classes. If it prevents attacks, it is a suitable security manager and allowed to remain. If
* it does not prevent attacks, this attempts to override the currently installed security manager and install itself.
* If the existing security manager prevents this from installing itself, an {@link InsecureEnvironmentException} is
* thrown and the LicenseManager fails to start.
*
* When this security manager installs itself over another, it will nest the other security manager within itself and
* call all appropriate checking methods on that other security manager after this manager performs its analog
* checks.
*
* When reflection is used to access non-public methods, fields, classes or interfaces, the JVM first consults the
* installed security manager to ensure that the access is permitted. This security manager throws an exception if the
* protected or private object being accessed via reflection belongs to the security manager package.
*
* Finally, this security manager will prevent other security managers from installing themselves over this one, so
* that these security measures are not compromised.
*
* @author Nick Williams
* @version 1.0.0
* @since 1.0.0
*/
final class LicenseSecurityManager extends SecurityManager {
private static LicenseSecurityManager instance;
private static final String FEATURE_RESTRICTION = FeatureRestriction.class.getCanonicalName();
private static final String SIGNED_LICENSE = SignedLicense.class.getCanonicalName();
private static final RuntimePermission CHECK_MEMBER_ACCESS_PERMISSION =
new RuntimePermission("accessDeclaredMembers");
private static final RuntimePermission SET_SECURITY_MANAGER_PERMISSION =
new RuntimePermission("setSecurityManager");
static {
final SecurityManager manager = System.getSecurityManager();
if (manager == null) {
// install the security manager
LicenseSecurityManager.installSecurityManagerWithParent(null);
} else if (!manager.getClass().equals(LicenseSecurityManager.class)) {
if (!LicenseSecurityManager.securityManagerIsSuitableReplacement(manager)) {
// if it's not a suitable replacement, reset the security manager
LicenseSecurityManager.installSecurityManagerWithParent(manager);
}
}
}
private static boolean securityManagerIsSuitableReplacement(final SecurityManager securityManager) {
if (securityManager == null)
throw new IllegalArgumentException("Parameter securityManager cannot be null!");
// Make sure we can't call java.lang.Class#getDeclared*() on License
try {
securityManager.checkMemberAccess(License.class, Member.DECLARED);
return false;
} catch (final SecurityException ignore) {
// this is a good thing
}
// Make sure we can't call java.lang.Class#getDeclared*() on LicenseManager
try {
securityManager.checkMemberAccess(LicenseManager.class, Member.DECLARED);
return false;
} catch (SecurityException ignore) {
// this is a good thing
}
// Make sure we can't call java.lang.System#setSecurityManager()
try {
securityManager.checkPermission(LicenseSecurityManager.SET_SECURITY_MANAGER_PERMISSION);
return false;
} catch (SecurityException ignore) {
// this is a good thing
}
return true;
}
private static void installSecurityManagerWithParent(final SecurityManager parent) {
try {
// install the security manager
LicenseSecurityManager.instance = new LicenseSecurityManager(parent);
System.setSecurityManager(LicenseSecurityManager.instance);
} catch (SecurityException e) {
// since we can't install the security manager, indicate that the environment is insecure
throw new InsecureEnvironmentException(e);
}
}
private final SecurityManager next;
private LicenseSecurityManager(final SecurityManager next) {
super();
this.next = next;
}
@Override
@SuppressWarnings("deprecation")
public void checkMemberAccess(final Class> reflectionClass,final int memberAccessType) {
if (reflectionClass == null) {
throw new IllegalArgumentException("Parameter reflectionClass cannot be null.");
}
this.inCheck = true;
try {
if (memberAccessType != Member.PUBLIC) {
/*
* We check class canonical name, not class object, for equivalency. This is because
* (SomeClass.class == SomeClass.class) evaluates to false when the classes are loaded by two different
* ClassLoaders and (SomeClass.class.equals(SomeClass.class)) evaluates to false when the classes are
* loaded by two different ClassLoaders. Only their class canonical names are guaranteed to be the same.
*/
final Package packageObject = reflectionClass.getPackage();
if (
packageObject != null &&
packageObject.getName().startsWith("ro.esolutions.licensing") &&
!reflectionClass.getCanonicalName().equals(LicenseSecurityManager.FEATURE_RESTRICTION) &&
!reflectionClass.getCanonicalName().equals(LicenseSecurityManager.SIGNED_LICENSE)
) {
throw new SecurityException("Reflection access to non-public members of LicenseManager class [" +
reflectionClass.getSimpleName() + "] prohibited.");
}
if (reflectionClass == java.lang.Class.class || reflectionClass == java.lang.System.class) {
Class stack[] = getClassContext();
if (stack.length < 4 || !stack[3].getPackage().getName().startsWith("java."))
throw new SecurityException("Reflection access to non-public members of java.lang.Class " +
"and java.lang.System prohibited.");
}
if (this.next != null) {
/*
* Per Java SE 6 documentation for java.lang.SecurityManager#checkMemberAccess: If this method is
* overridden, then a call to super.checkMemberAccess cannot be made, as the default implementation
* of checkMemberAccess relies on the code being checked being at a stack depth of 4. So, we
* copy-and-paste the implementation from Java SE 6.
*
* this.next.checkMemberAccess(reflectionClass, memberAccessType);
*
* Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
final Class stack[] = getClassContext();
/*
* stack depth of 4 should be the caller of one of the
* methods in java.lang.Class that invoke checkMember
* access. The stack should look like:
*
* someCaller [3]
* java.lang.Class.someReflectionAPI [2]
* java.lang.Class.checkMemberAccess [1]
* SecurityManager.checkMemberAccess [0]
*
*/
if ((stack.length < 4) || (stack[3].getClassLoader() != reflectionClass.getClassLoader())) {
this.checkPermission(LicenseSecurityManager.CHECK_MEMBER_ACCESS_PERMISSION);
}
}
}
} finally {
this.inCheck = false;
}
}
@Override
@SuppressWarnings("deprecation")
public void checkPermission(final Permission permission) {
this.inCheck = true;
try {
if (permission.getName().equals("setSecurityManager"))
throw new SecurityException("Setting a SecurityManager other than the LicenseSecurityManager is prohibited.");
if (this.next != null)
this.next.checkPermission(permission);
} finally {
this.inCheck = false;
}
}
@Override
public void checkPackageAccess(final String packageName) {
if (this.next != null) {
this.next.checkPackageAccess(packageName);
}
}
@Override
public void checkPermission(final Permission permission,final Object object) {
if (this.next != null) {
this.next.checkPermission(permission, object);
}
}
@Override
public void checkCreateClassLoader() {
if (this.next != null) {
this.next.checkCreateClassLoader();
}
}
@Override
public void checkAccess(final Thread thread) {
if (this.next != null) {
this.next.checkAccess(thread);
}
}
@Override
public void checkAccess(final ThreadGroup threadGroup) {
if (this.next != null) {
this.next.checkAccess(threadGroup);
}
}
@Override
public void checkExit(final int i) {
if (this.next != null) {
this.next.checkExit(i);
}
}
@Override
public void checkExec(final String s) {
if (this.next != null) {
this.next.checkExec(s);
}
}
@Override
public void checkLink(final String s) {
if (this.next != null) {
this.next.checkLink(s);
}
}
@Override
public void checkRead(final FileDescriptor fileDescriptor) {
if (this.next != null) {
this.next.checkRead(fileDescriptor);
}
}
@Override
public void checkRead(final String s) {
if (this.next != null)
this.next.checkRead(s);
}
@Override
public void checkRead(final String s,final Object o) {
if (this.next != null)
this.next.checkRead(s);
}
@Override
public void checkWrite(final FileDescriptor fileDescriptor) {
if (this.next != null)
this.next.checkWrite(fileDescriptor);
}
@Override
public void checkWrite(final String s) {
if (this.next != null)
this.next.checkWrite(s);
}
@Override
public void checkDelete(final String s) {
if (this.next != null)
this.next.checkDelete(s);
}
@Override
public void checkConnect(final String s,final int i) {
if (this.next != null)
this.next.checkConnect(s, i);
}
@Override
public void checkConnect(final String s,final int i,final Object o) {
if (this.next != null)
this.next.checkConnect(s, i, o);
}
@Override
public void checkListen(final int i) {
if (this.next != null)
this.next.checkListen(i);
}
@Override
public void checkAccept(final String s,final int i) {
if (this.next != null)
this.next.checkAccept(s, i);
}
@Override
public void checkMulticast(final InetAddress inetAddress) {
if (this.next != null)
this.next.checkMulticast(inetAddress);
}
@Override
@Deprecated
public void checkMulticast(final InetAddress inetAddress,final byte b) {
if (this.next != null)
this.next.checkMulticast(inetAddress, b);
}
@Override
public void checkPropertiesAccess() {
if (this.next != null)
this.next.checkPropertiesAccess();
}
@Override
public void checkPropertyAccess(final String s) {
if (this.next != null)
this.next.checkPropertyAccess(s);
}
@Override
public void checkPrintJobAccess() {
if (this.next != null)
this.next.checkPrintJobAccess();
}
@Override
@Deprecated
public void checkSystemClipboardAccess() {
if (this.next != null)
this.next.checkSystemClipboardAccess();
}
@Override
@Deprecated
public void checkAwtEventQueueAccess() {
if (this.next != null)
this.next.checkAwtEventQueueAccess();
}
@Override
public void checkPackageDefinition(final String s) {
if (this.next != null)
this.next.checkPackageDefinition(s);
}
@Override
public void checkSetFactory() {
if (this.next != null)
this.next.checkSetFactory();
}
@Override
public void checkSecurityAccess(final String s) {
if (this.next != null)
this.next.checkSecurityAccess(s);
}
@Override
@Deprecated
public boolean checkTopLevelWindow(final Object window) {
return this.next == null || this.next.checkTopLevelWindow(window);
}
@Override
public ThreadGroup getThreadGroup() {
return this.next != null ? this.next.getThreadGroup() : super.getThreadGroup();
}
@Override
public Object getSecurityContext() {
return this.next != null ? this.next.getSecurityContext() : super.getSecurityContext();
}
protected static LicenseSecurityManager getInstance() {
return LicenseSecurityManager.instance;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy