зеркало из https://github.com/mozilla/pluotsorbet.git
Merge pull request #56 from marco-c/native_security_handler
Use the native version of the SecurityHandler class
This commit is contained in:
Коммит
f141e496a0
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
|
@ -30,17 +30,16 @@ import javax.microedition.io.*;
|
|||
|
||||
import javax.microedition.lcdui.*;
|
||||
|
||||
import com.sun.j2me.security.AccessController;
|
||||
|
||||
import com.sun.midp.lcdui.*;
|
||||
|
||||
import com.sun.midp.midlet.*;
|
||||
|
||||
import com.sun.midp.i18n.Resource;
|
||||
import com.sun.midp.i18n.ResourceConstants;
|
||||
|
||||
import com.sun.midp.events.EventQueue;
|
||||
|
||||
import com.sun.midp.io.j2me.storage.*;
|
||||
import com.sun.midp.configurator.Constants;
|
||||
|
||||
import com.sun.midp.log.Logging;
|
||||
import com.sun.midp.log.LogChannels;
|
||||
|
@ -50,14 +49,6 @@ import com.sun.midp.log.LogChannels;
|
|||
* a MIDlet suite.
|
||||
*/
|
||||
public final class SecurityHandler {
|
||||
/** Session level interaction has not occured. */
|
||||
private final static byte NOT_ASKED = 0;
|
||||
|
||||
/** User granted permission for this session. */
|
||||
private final static byte GRANTED = 1;
|
||||
|
||||
/** User denied permission for this session. */
|
||||
private final static byte DENIED = -1;
|
||||
|
||||
/** The security token for this class. */
|
||||
private static SecurityToken classSecurityToken;
|
||||
|
@ -65,34 +56,21 @@ public final class SecurityHandler {
|
|||
/** The standard security exception message. */
|
||||
public static final String STD_EX_MSG = "Application not authorized " +
|
||||
"to access the restricted API";
|
||||
|
||||
/** Permission list. */
|
||||
private byte permissions[];
|
||||
|
||||
/** A flag for the session value of each permission. */
|
||||
private byte sessionValues[];
|
||||
|
||||
/** Maximum permission level list. */
|
||||
private byte maxPermissionLevels[];
|
||||
|
||||
/** True, if trusted. */
|
||||
private boolean trusted;
|
||||
|
||||
/**
|
||||
* Creates a security domain with a list of permitted actions or no list
|
||||
* to indicate all actions. The caller must be have permission for
|
||||
* <code>Permissions.MIDP</code> or be the first caller of
|
||||
* the method for this instance of the VM.
|
||||
*
|
||||
* @param apiPermissions for the token
|
||||
* @param ApiPermissions for the token
|
||||
* @param domain name of the security domain
|
||||
*
|
||||
* @exception SecurityException if caller is not permitted to call this
|
||||
* method
|
||||
*/
|
||||
public SecurityHandler(byte[] apiPermissions, String domain) {
|
||||
AccessController.checkPermission(Permissions.AMS_PERMISSION_NAME);
|
||||
init(apiPermissions, domain);
|
||||
public SecurityHandler(byte[] ApiPermissions, String domain) {
|
||||
// No-op since we don't cache any permissions in Java
|
||||
// Query native security manager every time
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,39 +80,16 @@ public final class SecurityHandler {
|
|||
* the method for this instance of the VM.
|
||||
*
|
||||
* @param securityToken security token of the caller
|
||||
* @param apiPermissions for the token, can be null
|
||||
* @param ApiPermissions for the token, can be null
|
||||
* @param domain name of the security domain
|
||||
*
|
||||
* @exception SecurityException if caller is not permitted to call this
|
||||
* method
|
||||
*/
|
||||
public SecurityHandler(SecurityToken securityToken,
|
||||
byte[] apiPermissions, String domain) {
|
||||
securityToken.checkIfPermissionAllowed(Permissions.AMS);
|
||||
init(apiPermissions, domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a security domain with a list of permitted actions or no list
|
||||
* to indicate all actions. The caller must be have permission for
|
||||
* <code>Permissions.MIDP</code> or be the first caller of
|
||||
* the method for this instance of the VM.
|
||||
*
|
||||
* @param apiPermissions for the token
|
||||
* @param domain name of the security domain
|
||||
*
|
||||
* @exception SecurityException if caller is not permitted to call this
|
||||
* method
|
||||
*/
|
||||
private void init(byte[] apiPermissions, String domain) {
|
||||
maxPermissionLevels =
|
||||
(Permissions.forDomain(domain))[Permissions.MAX_LEVELS];
|
||||
|
||||
permissions = apiPermissions;
|
||||
|
||||
sessionValues = new byte[permissions.length];
|
||||
|
||||
trusted = Permissions.isTrusted(domain);
|
||||
byte[] ApiPermissions, String domain) {
|
||||
// Do not cache anything
|
||||
// Ask native security manager everytime
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,46 +104,23 @@ public final class SecurityHandler {
|
|||
* -1 if the status is unknown
|
||||
*/
|
||||
public int checkPermission(String permission) {
|
||||
int i;
|
||||
int status = 0;
|
||||
int permId;
|
||||
|
||||
synchronized (this) {
|
||||
try {
|
||||
i = Permissions.getId(permission);
|
||||
} catch (SecurityException e) {
|
||||
return 0; //not found, report denied
|
||||
}
|
||||
try {
|
||||
permId = Permissions.getId(permission);
|
||||
MIDletSuite current =
|
||||
MIDletStateHandler.getMidletStateHandler().getMIDletSuite();
|
||||
|
||||
switch (permissions[i]) {
|
||||
case Permissions.ALLOW:
|
||||
case Permissions.BLANKET_GRANTED:
|
||||
// report allowed
|
||||
return 1;
|
||||
|
||||
case Permissions.SESSION:
|
||||
if (sessionValues[i] == GRANTED) {
|
||||
// report allowed
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sessionValues[i] == DENIED) {
|
||||
// report denied
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fall through
|
||||
case Permissions.BLANKET:
|
||||
case Permissions.ONESHOT:
|
||||
// report unknown
|
||||
return -1;
|
||||
|
||||
default:
|
||||
// Permissions.NEVER
|
||||
break;
|
||||
}
|
||||
|
||||
// report denied
|
||||
return 0;
|
||||
if (current != null) {
|
||||
// query native security mgr for status
|
||||
status = checkPermissionStatus0(current.getID(), permId);
|
||||
}
|
||||
} catch (SecurityException exc) {
|
||||
// intentionally ignored
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,9 +139,7 @@ public final class SecurityHandler {
|
|||
* the ID must be from
|
||||
* {@link com.sun.midp.security.Permissions}
|
||||
* @param title Resource constant for the title of the dialog
|
||||
* @param question Resource constant for the question to ask the user
|
||||
* @param oneshotQuestion Resource constant for the oneshot question to
|
||||
* ask the user
|
||||
* @param question Resource constant for the question to ask user
|
||||
* @param app name of the application to insert into a string
|
||||
* can be null if no %1 a string
|
||||
* @param resource string to insert into a string,
|
||||
|
@ -217,9 +147,8 @@ public final class SecurityHandler {
|
|||
* @param extraValue string to insert into a string,
|
||||
* can be null if no %3 in a string
|
||||
*
|
||||
* @return <code>true</code> if the permission interaction has permanently
|
||||
* changed and the new state should be saved, this will only happen
|
||||
* if the permission granted
|
||||
* @return true if the permission was allow and was not allowed
|
||||
* before
|
||||
*
|
||||
* @exception SecurityException if the permission is not
|
||||
* allowed by this token
|
||||
|
@ -232,7 +161,8 @@ public final class SecurityHandler {
|
|||
throws InterruptedException {
|
||||
|
||||
return checkForPermission(permission, title, question,
|
||||
oneshotQuestion, app, resource, extraValue, STD_EX_MSG);
|
||||
oneshotQuestion, app, resource, extraValue,
|
||||
SecurityToken.STD_EX_MSG);
|
||||
}
|
||||
|
||||
|
||||
|
@ -263,9 +193,8 @@ public final class SecurityHandler {
|
|||
* can be null if no %3 in a string
|
||||
* @param exceptionMsg message if a security exception is thrown
|
||||
*
|
||||
* @return <code>true</code> if the permission interaction has permanently
|
||||
* changed and the new state should be saved, this will only happen
|
||||
* if the permission granted
|
||||
* @return <code>true</code> if the permission was allowed and was
|
||||
* not allowed before; <code>false</code>, if permission is granted..
|
||||
*
|
||||
* @exception SecurityException if the permission is not
|
||||
* allowed by this token
|
||||
|
@ -273,89 +202,21 @@ public final class SecurityHandler {
|
|||
* calling thread while this method is waiting to preempt the
|
||||
* display.
|
||||
*/
|
||||
public boolean checkForPermission(String permissionStr, String title, String question,
|
||||
public boolean checkForPermission(String permission, String title, String question,
|
||||
String oneShotQuestion, String app, String resource, String extraValue,
|
||||
String exceptionMsg) throws InterruptedException {
|
||||
|
||||
MIDletSuite current =
|
||||
MIDletStateHandler.getMidletStateHandler().getMIDletSuite();
|
||||
|
||||
if (permissions == null) {
|
||||
/* totally trusted, all permissions allowed */
|
||||
return false;
|
||||
if (current != null) {
|
||||
// can throw SecurityException
|
||||
int permId = Permissions.getId(permission);
|
||||
if (checkPermission0(current.getID(), permId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
int permission;
|
||||
try {
|
||||
permission = Permissions.getId(permissionStr);
|
||||
} catch (SecurityException e) {
|
||||
throw new SecurityException(exceptionMsg);
|
||||
}
|
||||
if (permission >= 0 && permission < permissions.length) {
|
||||
switch (permissions[permission]) {
|
||||
case Permissions.ALLOW:
|
||||
case Permissions.BLANKET_GRANTED:
|
||||
return false;
|
||||
|
||||
case Permissions.BLANKET:
|
||||
/* This level means the question has not been asked yet. */
|
||||
if (askUserForPermission(classSecurityToken, trusted,
|
||||
title, question, app, resource, extraValue)) {
|
||||
|
||||
Permissions.setPermissionGroup(permissions,
|
||||
permission, Permissions.BLANKET_GRANTED);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Permissions.setPermissionGroup(permissions,
|
||||
permission, Permissions.BLANKET_DENIED);
|
||||
break;
|
||||
|
||||
case Permissions.SESSION:
|
||||
if (sessionValues[permission] == GRANTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sessionValues[permission] == DENIED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (askUserForPermission(classSecurityToken, trusted,
|
||||
title, question, app, resource, extraValue)) {
|
||||
/*
|
||||
* Save the fact that the question has already
|
||||
* been asked this session.
|
||||
*/
|
||||
Permissions.setPermissionGroup(sessionValues,
|
||||
permission, GRANTED);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the fact that the question has already
|
||||
* been asked this session.
|
||||
*/
|
||||
Permissions.setPermissionGroup(sessionValues,
|
||||
permission, DENIED);
|
||||
break;
|
||||
|
||||
case Permissions.ONESHOT:
|
||||
if (askUserForPermission(classSecurityToken, trusted,
|
||||
title, oneShotQuestion, app, resource,
|
||||
extraValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Permissions.NEVER
|
||||
break;
|
||||
} // switch
|
||||
} // if
|
||||
|
||||
throw new SecurityException(exceptionMsg);
|
||||
} // synchronized
|
||||
throw new SecurityException(STD_EX_MSG);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -363,10 +224,10 @@ public final class SecurityHandler {
|
|||
*
|
||||
* @param token security token with the permission to preempt the
|
||||
* foreground display
|
||||
* @param trusted true to display the trusted icon, false to display the
|
||||
* untrusted icon
|
||||
* @param title Resource constant for the title of the dialog
|
||||
* @param question Resource constant for the question to ask user
|
||||
* @param oneShotQuestion Resource constant for the oneshot question to
|
||||
* ask the user
|
||||
* @param app name of the application to insert into a string
|
||||
* can be null if no %1 a string
|
||||
* @param resource string to insert into a string,
|
||||
|
@ -383,12 +244,9 @@ public final class SecurityHandler {
|
|||
public static boolean askUserForPermission(SecurityToken token,
|
||||
boolean trusted, String title, String question, String app,
|
||||
String resource, String extraValue) throws InterruptedException {
|
||||
|
||||
PermissionDialog dialog =
|
||||
new PermissionDialog(token, trusted, title, question, app,
|
||||
resource, extraValue);
|
||||
|
||||
return dialog.waitForAnswer();
|
||||
// Allow Push interrupt since the decision is already made
|
||||
// at native Push level
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -404,168 +262,33 @@ public final class SecurityHandler {
|
|||
|
||||
classSecurityToken = token;
|
||||
}
|
||||
}
|
||||
|
||||
/** Implements security permission dialog. */
|
||||
class PermissionDialog implements CommandListener {
|
||||
/** Caches the display manager reference. */
|
||||
private DisplayEventHandler displayEventHandler;
|
||||
|
||||
/** Permission Alert. */
|
||||
private Alert alert;
|
||||
|
||||
/** Command object for "Yes" command. */
|
||||
private Command yesCmd =
|
||||
new Command(Resource.getString(ResourceConstants.YES),
|
||||
Command.OK, 1);
|
||||
/** Command object for "No" command. */
|
||||
private Command noCmd =
|
||||
new Command(Resource.getString(ResourceConstants.NO),
|
||||
Command.BACK, 1);
|
||||
/** Holds the preempt token so the form can end. */
|
||||
private Object preemptToken;
|
||||
|
||||
/** Holds the answer to the security question. */
|
||||
private boolean answer;
|
||||
|
||||
/**
|
||||
* Construct permission dialog.
|
||||
* <p>
|
||||
* The title, question, and answer strings will be translated,
|
||||
* if a string resource is available.
|
||||
* Since the strings can have substitution token in them, if there is a
|
||||
* "%" it must changed to "%%". If a string has a %1, the app parameter
|
||||
* will be substituted for it. If a string has a "%2, the resource
|
||||
* parameter will be substituted for it. If a string has a %3, the
|
||||
* extraValue parameter will be substituted for it.
|
||||
*
|
||||
* @param token security token with the permission to preempt the
|
||||
* foreground display
|
||||
* @param trusted true to display the trusted icon, false to display the
|
||||
* untrusted icon
|
||||
* @param title Resource constant for the title of the dialog
|
||||
* @param question Resource constant for the question to ask user
|
||||
* @param app name of the application to insert into a string
|
||||
* can be null if no %1 a string
|
||||
* @param resource string to insert into a string,
|
||||
* can be null if no %2 in a string
|
||||
* @param extraValue string to insert into a string,
|
||||
* can be null if no %3 in a string
|
||||
*
|
||||
* @exception InterruptedException if another thread interrupts the
|
||||
* calling thread while this method is waiting to preempt the
|
||||
* display.
|
||||
*/
|
||||
PermissionDialog(SecurityToken token, boolean trusted, String title,
|
||||
String question, String app, String resource, String extraValue)
|
||||
throws InterruptedException {
|
||||
String[] substitutions = {app, resource, extraValue};
|
||||
String iconFilename;
|
||||
RandomAccessStream stream;
|
||||
byte[] rawPng;
|
||||
Image icon;
|
||||
String configRoot = File.getConfigRoot(Constants.INTERNAL_STORAGE_ID);
|
||||
|
||||
alert = new Alert(Resource.getString(title, substitutions));
|
||||
|
||||
displayEventHandler =
|
||||
DisplayEventHandlerFactory.getDisplayEventHandler(token);
|
||||
|
||||
if (trusted) {
|
||||
iconFilename = configRoot + "trusted_icon.png";
|
||||
} else {
|
||||
iconFilename = configRoot + "untrusted_icon.png";
|
||||
}
|
||||
|
||||
stream = new RandomAccessStream(token);
|
||||
try {
|
||||
stream.connect(iconFilename, Connector.READ);
|
||||
rawPng = new byte[stream.getSizeOf()];
|
||||
stream.readBytes(rawPng, 0, rawPng.length);
|
||||
stream.disconnect();
|
||||
icon = Image.createImage(rawPng, 0, rawPng.length);
|
||||
alert.setImage(icon);
|
||||
} catch (java.io.IOException noImage) {
|
||||
}
|
||||
|
||||
alert.setString(Resource.getString(question, substitutions));
|
||||
alert.addCommand(noCmd);
|
||||
alert.addCommand(yesCmd);
|
||||
alert.setCommandListener(this);
|
||||
preemptToken = displayEventHandler.preemptDisplay(alert, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the user's answer.
|
||||
*
|
||||
* @return user's answer
|
||||
*/
|
||||
boolean waitForAnswer() {
|
||||
synchronized (this) {
|
||||
if (preemptToken == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
// Developer programming error
|
||||
throw new RuntimeException(
|
||||
"Blocking call performed in the event thread");
|
||||
}
|
||||
|
||||
try {
|
||||
wait();
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user's answer and notifies waitForAnswer and
|
||||
* ends the form.
|
||||
*
|
||||
* @param theAnswer user's answer
|
||||
*/
|
||||
private void setAnswer(boolean theAnswer) {
|
||||
synchronized (this) {
|
||||
answer = theAnswer;
|
||||
|
||||
/*
|
||||
* Since this may be the only display, clear the alert,
|
||||
* so the user will not be confused by alert text still
|
||||
* displaying.
|
||||
*
|
||||
* The case should happen when running TCK test MIDlets in
|
||||
* SVM mode.
|
||||
*/
|
||||
alert.setTitle(null);
|
||||
alert.setString(null);
|
||||
alert.setImage(null);
|
||||
alert.addCommand(new Command("", 1, 1));
|
||||
alert.removeCommand(noCmd);
|
||||
alert.removeCommand(yesCmd);
|
||||
|
||||
displayEventHandler.donePreempting(preemptToken);
|
||||
|
||||
notify();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to a command issued on security question form.
|
||||
*
|
||||
* @param c command activated by the user
|
||||
* @param s the Displayable the command was on.
|
||||
*/
|
||||
public void commandAction(Command c, Displayable s) {
|
||||
if (c == yesCmd) {
|
||||
setAnswer(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setAnswer(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query native security manager for permission.
|
||||
* This call may block if user needs to be asked.
|
||||
*
|
||||
* @param suiteId the MIDlet suite the permission should be checked against
|
||||
* @param permission the permission id
|
||||
*
|
||||
* @return true if permission is granted. Otherwise, false.
|
||||
*/
|
||||
private native boolean checkPermission0(int suiteId, int permission);
|
||||
|
||||
/**
|
||||
* Get the status of the specified permission.
|
||||
* This is to implement public API MIDlet.checkPermission()
|
||||
* and will not block calling thread.
|
||||
*
|
||||
* If no API on the device defines the specific permission
|
||||
* requested then it must be reported as denied.
|
||||
* If the status of the permission is not known because it might
|
||||
* require a user interaction then it should be reported as unknown.
|
||||
*
|
||||
* @param suiteId the MIDlet suite the permission should be checked against
|
||||
* @param permission to check if denied, allowed, or unknown.
|
||||
* @return 0 if the permission is denied; 1 if the permission is allowed;
|
||||
* -1 if the status is unknown
|
||||
*/
|
||||
private native int checkPermissionStatus0(int suiteId,
|
||||
int permission);
|
||||
}
|
||||
|
|
10
midp/midp.js
10
midp/midp.js
|
@ -1140,3 +1140,13 @@ Native["com/ibm/oti/connection/file/FCOutputStream.writeImpl.([BIII)V"] = functi
|
|||
|
||||
_this.pos += count;
|
||||
}
|
||||
|
||||
Native["com/sun/midp/security/SecurityHandler.checkPermission0.(II)Z"] = function(ctx, stack) {
|
||||
var permission = stack.pop(), suiteId = stack.pop(), _this = stack.pop();
|
||||
stack.push(1);
|
||||
}
|
||||
|
||||
Native["com/sun/midp/security/SecurityHandler.checkPermissionStatus0.(II)I"] = function(ctx, stack) {
|
||||
var permission = stack.pop(), suiteId = stack.pop(), _this = stack.pop();
|
||||
stack.push(1);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,9 @@ Native["java/lang/System.getProperty0.(Ljava/lang/String;)Ljava/lang/String;"] =
|
|||
case "microedition.platform":
|
||||
value = "NOKIA503/JAVA_RUNTIME_VERSION=NOKIA_ASHA_1_2";
|
||||
break;
|
||||
case "microedition.profiles":
|
||||
value = "MIDP-2.0"
|
||||
break;
|
||||
case "fileconn.dir.memorycard":
|
||||
value = "fcfile:///";
|
||||
break;
|
||||
|
|
Загрузка…
Ссылка в новой задаче