SecurityManager is now gold, hopefully. Interfaces are fully javadoc'd, should be ready to release finally.

This commit is contained in:
Travis Burtrum 2010-05-04 03:46:24 -04:00 committed by moparisthebest
parent a964437d1a
commit 7436e5405e
5 changed files with 176 additions and 61 deletions

View File

@ -27,6 +27,7 @@ import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class client extends RSApplet {
@ -92,7 +93,7 @@ public class client extends RSApplet {
return serverPort;
}
public HashMap<String, String> getParams() {
public Map<String, String> getParams() {
HashMap<String, String> ret = new HashMap<String, String>();
// set params
ret.put("getCodeBase", "http://localhost");

View File

@ -10,6 +10,7 @@ import java.awt.image.PixelGrabber;
import java.net.Socket;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
public class client extends Applet_Sub1 implements ClientInterface {
@ -69,7 +70,7 @@ public class client extends Applet_Sub1 implements ClientInterface {
return serverPort;
}
public HashMap<String, String> getParams() {
public Map<String, String> getParams() {
HashMap<String, String> ret = new HashMap<String, String>();
// set params
ret.put("getCodeBase", "http://localhost");

View File

@ -21,44 +21,156 @@
package org.moparscape.iface;
/**
* This interface must be implemented for moparscape to load this applet as a client.
* For two different working examples, check the 317 and 508 clients implementing this interface.
* <p/>
* The only methods that *MUST* be implemented correctly are the ones that say so, namely setServer, setPort, getPort,
* setCacheDir, setKeyListener, and getParams.
*
* @author mopar
*/
public interface ClientInterface {
public static final long serialVersionUID = 42L;
public static final long serialVersionUID = 43L;
/**
* Sets the server address the user wishes to connect to.
* <p/>
* This *MUST* be implemented correctly.
*
* @param server The address of the private server the client should connect to next time 'login' is pressed.
*/
public void setServer(String server);
/**
* Sets the port of the private server the user wishes to connect to.
* <p/>
* This *MUST* be implemented correctly.
*
* @param port The port number to be used when connecting to the server.
*/
public void setPort(int port);
public void setCacheDir(String cacheDir);
public void setOndemandPort(int port);
public void setJaggrabPort(int port);
public void setMapLock(boolean maplock, int mapface);
public void setHPheads(boolean on);
public void setZoom(boolean on);
public void setKeyListener(java.awt.event.KeyListener kl);
public void modZoomInts(int zoom, int fwdbwd, int lftrit);
/**
* Returns the server's port.
* <p/>
* This *MUST* be implemented correctly.
*
* @return The port the client would try to connect to, as set by setPort().
*/
public int getPort();
/*
These are only meant to be called once.
/**
* Tells the client where the cache will reside, this is the only folder the client has write permissions to.
* <p/>
* This *MUST* be implemented correctly.
*
* @param cacheDir The directory the cache files for the client are in.
*/
public java.util.HashMap<String, String> getParams();
public void setCacheDir(String cacheDir);
// should always return org.moparscape.userver.Server[2]
/**
* Gives the client a KeyListener to send left-over keyPressed events back to that the client doesn't recognize.
* This is needed because the client grabs all key events and moparscape doesn't receive them,
* causing the key bindings not to work. The way to implement this is to find your 'keyPressed(KeyEvent keyevent)'
* method in your client, and at the end of it add 'client.keyListener.keyPressed(keyevent);', assuming
* you save this 'kl' as client.keyListener.
* <p/>
* This *MUST* be implemented correctly.
*
* @param kl KeyListener to save and send events back to.
*/
public void setKeyListener(java.awt.event.KeyListener kl);
/**
* Tells the client what port on localhost the Ondemand server is listening on.
* If this client doesn't use this server, you can ignore this call.
*
* @param port The port the server is listening on on the localhost address.
*/
public void setOndemandPort(int port);
/**
* Tells the client what port on localhost the Jaggrab server is listening on.
* If this client doesn't use this server, you can ignore this call.
*
* @param port The port the server is listening on on the localhost address.
*/
public void setJaggrabPort(int port);
/**
* Turns maplock on or off and also sets the direction the map should be locked to.
* If you don't have this functionality, just ignore this call. (currently 508 does)
*
* @param maplock True for on, false for off.
* @param mapface 0 for North, 1030 for South, 1545 for East, 515 for West. Look at 317 for reference.
*/
public void setMapLock(boolean maplock, int mapface);
/**
* Turns HP over heads on or off.
* If you don't have this functionality, just ignore this call. (currently 508 ignores it)
*
* @param on True for on, false for off.
*/
public void setHPheads(boolean on);
/**
* Turns camera zoom on or off.
* If you don't have this functionality, just ignore this call. (currently 508 ignores it)
*
* @param on True for on, false for off.
*/
public void setZoom(boolean on);
/**
* Modifies the camera zoom and position.
* For example functionality, look at moparscape's 317.
* If you don't have this functionality, just ignore this call. (currently 508 ignores it)
*
* @param zoom The amount to add to the zoom integer.
* @param fwdbwd The amount to add to the fwdbwd integer.
* @param lftrit The amount to add to the lftrit integer.
*/
public void modZoomInts(int zoom, int fwdbwd, int lftrit);
// The following are only meant to be called once.
/**
* Moparscape feeds these parameters back to the client when it requests them, just like a browser would.
* <p/>
* This *MUST* be implemented correctly.
*
* @return A Map with the param name as the key, and the value as the value.
*/
public java.util.Map<String, String> getParams();
/**
* Called once to get update servers for moparscape to start and manage.
*
* @param defaultLocation Default location of cache.
* @param customLocation Custom location of cache.
* @return Should always return org.moparscape.userver.Server[2] (but each index can be null)
*/
public org.moparscape.userver.Server[] getUpdateServers(String defaultLocation, String customLocation);
/**
* Called to get the size of the client.
* Currently moparscape ignores this and assumes it to be 765x503,
* this will change in the near future though when support for
* HD (and non-standard size SD) clients is added.
*
* @return Size of client.
*/
public java.awt.Dimension getDimension();
/**
* Sets the background the client should use.
* Optional, but much better if you use it.
*
* @param image Image to use as the client background.
*/
public void setBackground(java.awt.Image image);
}

View File

@ -21,6 +21,8 @@
package org.moparscape.iface;
/**
* This interface must be implemented for moparscape to load this as a server.
* For two different working examples, check the 317 and 508 clients implementing this interface.
* @author mopar
*/
public interface ServerInterface {

View File

@ -24,7 +24,6 @@ import org.moparscape.MainPanel;
import java.security.Permission;
import java.security.Permissions;
import java.util.HashMap;
import java.util.Map;
/**
@ -33,7 +32,9 @@ import java.util.Map;
*/
public class SecurityManager extends java.lang.SecurityManager {
private Map<ClassLoader, Permissions> permissionMap = new HashMap<ClassLoader, Permissions>();
// IdentityHashMap is faster than HashMap and better in this case as the ClassLoader is the SAME OBJECT
// and therefore will compare better and faster with == rather than the .equals() HashMap uses
private Map<ClassLoader, Permissions> permissionMap = new java.util.IdentityHashMap<ClassLoader, Permissions>();
// single socket permission that is allowed
private java.net.SocketPermission allowedSocket = new java.net.SocketPermission("localhost", "connect,accept,resolve");
@ -43,14 +44,6 @@ public class SecurityManager extends java.lang.SecurityManager {
private Permission reflectPerm = new java.lang.reflect.ReflectPermission("suppressAccessChecks");
private Permission classLoaderPerm = new java.lang.RuntimePermission("createClassLoader");
public SecurityManager() {
try {
new java.net.URL("http://localhost/");
} catch (Exception e) {
}
}
public void addPermissions(ClassLoader cl, Permissions perms) {
// if they can't set the SecurityManager, they shouldn't be able to modify this one, so check...
System.getSecurityManager().checkPermission(new java.lang.RuntimePermission("setSecurityManager"));
@ -90,14 +83,10 @@ public class SecurityManager extends java.lang.SecurityManager {
// this isn't ready to go live yet, so just return and allow it all
//if (true) return;
// if this is the allowed socket, allow it
if (allowedSocket.implies(perm))
return;
// we are now going to go through the ClassLoaders of all Classes on the stack
// if any of them are in perms, then check the permissions, sticking to the most
// restrictive of the permissions of any class in the stack (ANDing them all together)
// so default value should be true or it would never be true ((false & anything) == false)
boolean allow = true;
// restrictive of the permissions of any class in the stack (if any are false, deny the request)
// get all classes on stack
Class c[] = getClassContext();
@ -106,17 +95,26 @@ public class SecurityManager extends java.lang.SecurityManager {
if (c[2].getName().equals("org.moparscape.security.SecurityManager"))
return;
//System.out.println("requesting perm: "+perm);
//System.out.println("requesting perm: " + perm);
for (int i = 1; i < c.length; i++) {
ClassLoader cl = c[i].getClassLoader();
// if the ClassLoader is null (can it be?) continue...
if (cl == null)
continue;
// getClassLoader() can return null, if it is the bootstrap class
// loader, since our Map implementation handles nulls, go ahead
// and ignore whether or not it is null (my tests show speed is the same)
//if (cl == null) continue;
Permissions clPerms = permissionMap.get(cl);
// if the classloader isn't in our map, we don't have any say on it so continue
if (clPerms == null)
continue;
// if the permissions allows this, continue and avoid all the following time-consuming checks
// TODO: I've since discovered .implies() is rather slow, so find out what is slower, this or the following...
if (clPerms.implies(perm))
continue;
// 2 exceptions here for java.util.GregorianCalendar, java.util.Calendar, java.text.SimpleDateFormat:
// java.lang.RuntimePermission accessClassInPackage.sun.util.resources
// java.lang.reflect.ReflectPermission suppressAccessChecks
@ -152,26 +150,27 @@ public class SecurityManager extends java.lang.SecurityManager {
return;
}
}
// it must be in our map, so update allow appropriatly
allow &= clPerms.implies(perm);
// one last check, which I found is very slow
// if this is the allowed socket, allow it
if (allowedSocket.implies(perm))
return;
// if we get all the way down here, the permission was denied and wasn't an exception, so throw an exception
System.err.println("denying: " + perm.toString());
if (org.moparscape.MainPanel.debug()) {
// class stack for debugging
for (int x = 1; x < c.length; x++) System.out.println(x + ": " + c[x].getName());
Thread.dumpStack();
}
// otherwise allow is false, throw a SecurityException
throw new SecurityException("Permission denied: " + perm.toString());
//return;
}
// if allow is true, just return to allow the permission
if (allow)
return;
System.err.println("denying: " + perm.toString());
if (org.moparscape.MainPanel.debug()) {
// class stack for debugging
for (int i = 1; i < c.length; i++) System.out.println(i + ": " + c[i].getName());
Thread.dumpStack();
}
// otherwise allow is false, throw a SecurityException
//throw new SecurityException("Permission denied: " + perm.toString());
}
@Override