I'm trying to block certain actions from players but not from my game infrastructure and for that I'm using a security manager. It looks like this
public class GameSecurityManager extends SecurityManager {
@Override
public void checkPackageAccess(String pkg) {
super.checkPackageAccess(pkg);
if (isPlayer()) {
if (pkg.startsWith("ca.hilikus.jrobocom")) {
if (!"ca.hilikus.jrobocom.player".equals(pkg) && !"ca.hilikus.jrobocom.robot.api".equals(pkg)) {
throw new SecurityException("No access to game packages");
}}}
}
}
The documentation on security managers is very sparse and most of it is from the 90s. The AccessController situation is even worse. However, I did find this, section 6.2 where it states
We encourage the use of AccessController in application code, while customization of a security manager (via subclassing) should be the last resort and should be done with extreme care.
do you agree with the statement? Can someone explain why that is? if that is the case, how would I accomplish something similar to the sample code I pasted? I'm trying to block things like reflection, threading and instantiating some objects based on the context (like with isPlayer()
above). The only thing the Access Control javadoc discusses is privileged operations inside a special block of code, but it doesn't show how to use the controller to actually block actions
You don't need to write your own SecurityManager nor your own AccessController, what you need is a custom Permission. After you write one you only need to boot up a SecurityManager and do a security check in every method you want to protect! You might need to do a priveleged action to avoid to much check propagation. :)
(For the benefit of future users)
The answer to this is that you should provide a Security Policy for the application. If that is not possible to control, then you are simply out of luck.
In the policy, you would grant access to some suitable subset for your "hosted extensions", where as your "game packages" would be granted AllPermissions. Then, you create Permissions for your library and grant suitable access to the "hosted extensions".
Then in your APIs, you would do something like;
public String someMethod( String someArg )
{
if( System.getSecurityManager() == null )
return internalSomeMethod( someArg );
MyPermission required = new MyPermission( "whatever" );
AccessController.checkPermission( required );
return AccessController.doPrivileged(new PrivilegedAction<String>()
{
public String run()
{
return internalSomeMethod( somArg );
}
} );
}
private String someInternalMethod( String someArg ){...}
So, even if the "hosted extensions" ONLY have "MyPermission", the game engine can have AllPermissions and allowed to do anything it wants, whereas the "extension" couldn't even read a System Property.
Quote from section "6.4.9 SecurityManager
versus AccessController
" of the book Inside Java 2 Platform Security:
Recall from earlier in this chapter the difference, when invoking a security check, between calling checkPermission
and calling the other check
methods defined in the SecurityManager
class. The choice then was contingent on whether you depended on any pre–Java 2 security manager classes. Now you have another choice: calling either the checkPermission
method defined in SecurityManager
or the one defined in AccessController
. These methods differ in two major ways.
First, sometimes no installed SecurityManager
exists, so you cannot invoke check
or checkPermission
methods on it. By contrast, the static methods in AccessController
are always available to be called. Recall the following idiom for calling SecurityManager
:
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(permission);
But you can always call
AccessController.checkPermission(permission);
Thus, regardless of whether a systemwide SecurityManager
has been installed, if you want to ensure that your security check is always invoked, you should call AccessController
. Note, however, that some existing applications test whether there is an installed instance of SecurityManager
. Then, based on the result of this test, which signifies one or the other security states, these applications take different actions. For the backward compatibility of these applications, calling SecurityManager
is more appropriate.
The second difference is that calling SecurityManager
does not guarantee a particular access control algorithm; someone might have extended it and installed a custom security manager. By contrast, calling AccessController
guarantees that the full access control algorithm specified earlier is used. Thus, if you do not want to delegate your security check to a custom security manager, you should call AccessController
directly. Otherwise, call SecurityManager
.
Also, be warned that because the SecurityManager
class defines a general interface for security checks, it does not provide the privilege mechanism that AccessController
has defined. In fact, if you use the privilege mechanism in your code but later call SecurityManager
to perform a security check, the privilege status might not be taken into account if the security manager you installed is not the one provided by Java 2 and does not consult AccessController
or its equivalent.
You might wonder why we provide these choices. Isn't one way of doing things good enough? These choices are based on experience. A balanced trade-off between generality and consistency is needed. In the long run, we expect that custom security managers will not often be needed and that, even when they are defined, they will be built on existing functionality in AccessController
. In particular, they will provide additional functionality rather than promote incompatible behavior. Nevertheless, in a special environment in which a vastly different sort of security policy must be enforced, a customized security manager conceivably might not be able to use the algorithms implemented by AccessController
.
You can also take a look at SecurityManager versus AccessController section in Oracle's Java Platform, Standard Edition Security Developer’s Guide.