--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/security/javasrc/com/nokia/mj/impl/security/midp/authorization/AccessControllerImpl.java Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,454 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package com.nokia.mj.impl.security.midp.authorization;
+
+import java.security.Permission;
+import java.util.Vector;
+import java.security.AccessControlException;
+import com.nokia.mj.impl.utils.Uid;
+import com.nokia.mj.impl.security.midp.common.PolicyBasedPermissionImpl;
+import com.nokia.mj.impl.security.midp.common.UserPermission;
+import com.nokia.mj.impl.security.midp.common.UserSecuritySettings;
+import com.nokia.mj.impl.security.midp.common.PermissionMappingTable;
+import com.nokia.mj.impl.security.midp.common.MIDPPermission;
+import com.nokia.mj.impl.security.midp.common.GeneralSecuritySettings;
+import com.nokia.mj.impl.security.midp.common.SecurityExtensionsReader;
+import com.nokia.mj.impl.security.common.PermissionBase;
+import com.nokia.mj.impl.security.midp.storage.*;
+import com.nokia.mj.impl.storage.StorageSession;
+import com.nokia.mj.impl.utils.exception.UserCancelException;
+
+/**
+ * MIDP specific AccessController.
+ * At installation time, a MIDlet suite is granted a set of permissions.
+ * At runtime, when the MIDlet is trying to access some protected
+ * functionality, AccessController consults the set of granted permissions
+ * to decide if the MIDlet is allowed to access the protected
+ * functionality or not.
+ * The MIDP access control is based on the imply mechanism applied on the
+ * MIDlet suite's set of effective permissions.
+ */
+public final class AccessControllerImpl
+{
+ // each instance has a list of granted permissions and an associated prompt handler
+ private Uid iAppUID;
+ private SecurityPromptHandler iSecurityPromptHandler;
+ private StorageSession iStorageSession;
+
+ /**
+ * Checks if the calling entity (e.g. MIDlet suite) has access to
+ * functionality protected by given permission. If the permission is
+ * allowed by the security policy, this method returns normally;
+ * otherwise, it throws an AccessControlException.
+ * Caller of this method is prompted if the given permission is
+ * implied by a USER permission
+ * @param p Permission to be checked
+ * @throws AccessControlException is permission is not granted
+ */
+ public void checkPermission(Permission p)
+ {
+ SecurityStorage storage = new SecurityStorage(iStorageSession);
+ try
+ {
+ // resolve the given permission against the set of granted permissions
+ Vector resolvedPermissions = queryPermission(p, storage);
+
+ // if the permission was resolved, check if granting it requires
+ // user interaction
+ boolean unresolvedUserPermission = false;
+ for (int i=0; i<resolvedPermissions.size(); i++)
+ {
+ PolicyBasedPermissionImpl resolvedPermission =
+ (PolicyBasedPermissionImpl)resolvedPermissions.elementAt(i);
+ if (resolvedPermission.getUserSecuritySettings() != null)
+ {
+ if (resolvedPermission.getPromptDetails() != null)
+ {
+ handleUserPermission(p, resolvedPermission, storage);
+ return;
+ }
+ else
+ {
+ // user permission without prompt info
+ unresolvedUserPermission = true;
+ }
+ }
+ else
+ {
+ // the permission was implied by a non user permission as well
+ // -> reset the flag for user permission
+ unresolvedUserPermission = false;
+ }
+ }
+ if (unresolvedUserPermission)
+ {
+ // the checked permission was implied by only by user permission(s)
+ // for which there were no prompt details (user could not be
+ // prompted) -> fail
+ fail(p);
+ }
+ }
+ finally
+ {
+ storage.close();
+ }
+ }
+
+ /**
+ * Checks if the calling entity (e.g. MIDlet suite) has access to
+ * functionality protected by given permission (identified by name).
+ *
+ * @param permissionName Name of the permission to be checked
+ * @return 0 if the permission is denied
+ * 1 if the permission is allowed
+ * -1 if the status of the permission is
+ * unknown due to e.g. it requires user interaction
+ */
+ public int checkPermission(String permissionName)
+ {
+ Permission permission = getPermissionInstance(permissionName);
+ if (permission == null)
+ {
+ // unknown permission -> it is denied
+ return 0;
+ }
+ SecurityStorage storage = new SecurityStorage(iStorageSession);
+ try
+ {
+ // resolve the given permission against the set of granted permissions
+ Vector resolvedPermissions = PermissionResolver.resolvePermission(
+ storage.getStorageSession(), iAppUID, permission);
+
+ if (resolvedPermissions == null)
+ {
+ // denied permission
+ return 0;
+ }
+
+ // if the permission was resolved, check if granting it requires
+ // user interaction
+ for (int i=0; i<resolvedPermissions.size(); i++)
+ {
+ PolicyBasedPermissionImpl resolvedPermission =
+ (PolicyBasedPermissionImpl)resolvedPermissions.elementAt(i);
+ if (resolvedPermission.getUserSecuritySettings() != null)
+ {
+ // user permission: check the user settings
+ UserSecuritySettings settings = resolvedPermission
+ .getUserSecuritySettings();
+ switch (settings.getCurrentInteractionMode())
+ {
+ case UserSecuritySettings.ONESHOT_INTERACTION_MODE:
+ // requires user interaction
+ return -1;
+ case UserSecuritySettings.NO_INTERACTION_MODE:
+ // denied
+ return 0;
+ case UserSecuritySettings.BLANKET_INTERACTION_MODE:
+ // if prompt in blanket mode was shown then return 1
+ // otherwise return -1
+ boolean blanketPromptShown = storage
+ .readUserSecuritySettingsPromptFlag(
+ iAppUID, settings.getName());
+ return (blanketPromptShown ? 1 : -1);
+ case UserSecuritySettings.SESSION_INTERACTION_MODE:
+ return iSecurityPromptHandler
+ .getSessionPromptStatus(settings.getName());
+ }
+ }
+ }
+ }
+ finally
+ {
+ storage.close();
+ }
+ return 1;
+ }
+
+
+ /**
+ * Checks if the calling entity (e.g. MIDlet suite) has access to
+ * functionality protected by given permission (identified by name).
+ *
+ * @param permissionName Name of the permission to be checked
+ * @return true if the permission is allowed
+ * false if the permission is denied
+ */
+ public boolean isPermissionAllowed(String permissionName)
+ {
+ Permission permission = getPermissionInstance(permissionName);
+ if (permission == null)
+ {
+ // unknown permission -> it is denied
+ return false;
+ }
+ try
+ {
+ checkPermission(permission);
+ }
+ catch (AccessControlException e)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public AccessControllerImpl(StorageSession aStorageSession, Uid aAppSuiteUid, String aAppName)
+ {
+ init(aStorageSession, aAppSuiteUid, aAppName);
+ }
+
+ /**
+ * Closes the storage session
+ */
+ public void destroy()
+ {
+ iSecurityPromptHandler.destroy();
+ }
+
+
+ /**
+ * Does the initialization: initializes the prompt handler and and
+ * the storage
+ */
+ private void init(StorageSession aStorageSession, Uid appUID, String appName)
+ {
+ this.iAppUID = appUID;
+ this.iStorageSession = aStorageSession;
+ iSecurityPromptHandler = new SecurityPromptHandler(appName,
+ GeneralSecuritySettings.getSecurityWarningsMode(iStorageSession, appUID));
+ }
+
+ private Vector queryPermission(Permission p, SecurityStorage storage)
+ {
+ // resolve the given permission against the set of granted permissions
+ Vector resolvedPermissions =
+ PermissionResolver.resolvePermission(
+ storage.getStorageSession(), iAppUID, p);
+
+ // if permission not resovled FAIL
+ if (resolvedPermissions == null)
+ {
+ fail(p);
+ }
+ return resolvedPermissions;
+ }
+
+
+ /**
+ * Handles the user settings by delegating the prompt handler to handle
+ * the settings and stores the result as the new settings
+ */
+ private void handleUserPermission(
+ Permission checkedPermission,
+ UserPermission resolvedPermission,
+ SecurityStorage storage)
+ {
+ UserSecuritySettings settings = resolvedPermission
+ .getUserSecuritySettings();
+
+ // check if the settings are set to NO
+ if (settings.getCurrentInteractionMode()
+ == UserSecuritySettings.NO_INTERACTION_MODE)
+ {
+ fail(checkedPermission);
+ }
+
+ // check if the permission explicitly denies showing of the prompt
+ if (!resolvedPermission.getPromptDetails().isSecurityPromptNeeed(
+ settings.getCurrentInteractionMode()))
+ {
+ // no sense in going further
+ return;
+ }
+
+ boolean OFF = false;
+ boolean ON = true;
+
+ // "blanket" mode MUST prompt the user only once
+ // on or before the first invocation of the API or function protected.
+ boolean blanketPromptShown = storage
+ .readUserSecuritySettingsPromptFlag(iAppUID, settings.getName());
+
+ // give it to PromptHandler
+ UserSecuritySettings newSettings;
+ try
+ {
+ newSettings = iSecurityPromptHandler.handleUserPermission(
+ resolvedPermission, blanketPromptShown);
+ }
+ catch (UserCancelException e)
+ {
+ // add the AccessControlException as embedded exception
+ throw new UserCancelException(
+ e.getMessage(),
+ new java.security.AccessControlException(
+ "Permission " + checkedPermission + " not allowed"));
+ }
+
+ // if settings have not changed, still do one check on the current
+ // interaction mode: if it's blanket, mark down that the prompt in
+ // blanket mode was shown and then simply return
+ if (newSettings.equals(settings))
+ {
+ if (newSettings.getCurrentInteractionMode()
+ == UserSecuritySettings.BLANKET_INTERACTION_MODE
+ && !blanketPromptShown)
+ {
+ storage.writeUserSecuritySettingsPromptFlag(iAppUID,
+ settings.getName(), ON);
+ }
+ return;
+ }
+
+ if (newSettings.getCurrentInteractionMode()
+ == UserSecuritySettings.NO_INTERACTION_MODE)
+ {
+ // denying from runtime prompts will not change the settings
+ // to NO -> it is always a onetime deny (this has been chosen
+ // for a better user experience)
+ fail(checkedPermission);
+ }
+
+ if (settings.getCurrentInteractionMode()
+ == UserSecuritySettings.BLANKET_INTERACTION_MODE
+ && newSettings.getCurrentInteractionMode()
+ != UserSecuritySettings.BLANKET_INTERACTION_MODE)
+ {
+ // if mode is changed from blanket to something else than blanket,
+ // reset the flag indicating if prompting happened in blanket mode
+ blanketPromptShown = OFF;
+ }
+ else if (newSettings.getCurrentInteractionMode()
+ == UserSecuritySettings.BLANKET_INTERACTION_MODE)
+ {
+ // if mode is changed to blanket, set the flag indicating that
+ // prompt happened in blanket mode, since the change to blanket
+ // mode was made via a prompt
+ blanketPromptShown = ON;
+ }
+
+ // write the new settings to storage
+ storage.writeUserSecuritySettings(iAppUID, newSettings.getName(),
+ newSettings.getCurrentInteractionMode(), blanketPromptShown);
+ // inform the PermissionResolver that the settings have changed
+ PermissionResolver.settingsChanged(iAppUID, newSettings);
+ /* Uncomment if the mutual exclusive rules are to be applied in runtime security prompts
+ // apply the mutually exclusive rules
+ applyMutualExclusiveRules(storage, newSettings);
+ */
+ }
+
+ private Permission getPermissionInstance(String permissionName)
+ {
+ if (permissionName != null)
+ {
+ MIDPPermission internalPermission = PermissionMappingTable.get(
+ permissionName);
+ if (internalPermission == null)
+ {
+ internalPermission = SecurityExtensionsReader.getExtPermission(permissionName);
+ }
+ if (internalPermission != null)
+ {
+ // make an instance of the internal permission
+ try
+ {
+ return (Permission)ClassInstantiator.newInstance(
+ internalPermission.getName(),
+ internalPermission.getTarget(),
+ internalPermission.getActionList());
+ }
+ catch (InstantiationException e)
+ {
+ // fall-through
+ }
+ }
+ }
+ // fall-through
+ return null;
+ }
+
+ private void fail(Permission p)
+ {
+ throw new java.security.AccessControlException(
+ "Permission " + p + " not allowed");
+ }
+
+ private void applyMutualExclusiveRules(SecurityStorage storage, UserSecuritySettings settings)
+ {
+ // Rule1: if the settings belongs to list 1, change the settings
+ // to Session or Oneshot or No for all the settings belonging
+ // to list 2
+ // Rule2: if the settings belongs to list 2, change the settings
+ // to Session or Oneshot or No for all the settings belonging
+ // to list 1
+ // where
+ // list 1: Application Auto Invocation
+ // list 2: Net Access
+ boolean settings_in_list1 = (settings.getName().equalsIgnoreCase(
+ UserSecuritySettings.APPLICATION_AUTO_INVOCATION_SETTINGS));
+ boolean settings_in_list2 = (settings.getName().equalsIgnoreCase(
+ UserSecuritySettings.NET_ACCESS_SETTINGS));
+ if (settings.getCurrentInteractionMode()
+ != UserSecuritySettings.BLANKET_INTERACTION_MODE
+ || (settings_in_list1 == false && settings_in_list2 == false))
+ {
+ // not applicable
+ return;
+ }
+ String mutualExclusiveSettingsName = (settings_in_list1
+ ? UserSecuritySettings.NET_ACCESS_SETTINGS
+ : UserSecuritySettings.APPLICATION_AUTO_INVOCATION_SETTINGS);
+ UserSecuritySettings[] allSettings =
+ storage.readUserSecuritySettings(iAppUID);
+ for (int i=0; i<allSettings.length; i++)
+ {
+ if (allSettings[i].getName().equals(mutualExclusiveSettingsName)
+ && allSettings[i].getCurrentInteractionMode()
+ == UserSecuritySettings.BLANKET_INTERACTION_MODE)
+ {
+ // change the mutualExclusiveSettings to either
+ // Session or Oneshot or No
+ int mutualExclusiveSettingsIntractionMode;
+ if (allSettings[i].isInteractionModeAllowed(
+ UserSecuritySettings.SESSION_INTERACTION_MODE))
+ {
+ mutualExclusiveSettingsIntractionMode =
+ UserSecuritySettings.SESSION_INTERACTION_MODE;
+ }
+ else if (allSettings[i].isInteractionModeAllowed(
+ UserSecuritySettings.ONESHOT_INTERACTION_MODE))
+ {
+ mutualExclusiveSettingsIntractionMode =
+ UserSecuritySettings.ONESHOT_INTERACTION_MODE;
+ }
+ else
+ {
+ mutualExclusiveSettingsIntractionMode =
+ UserSecuritySettings.NO_INTERACTION_MODE;
+ }
+ storage.writeUserSecuritySettings(iAppUID,
+ mutualExclusiveSettingsName,
+ mutualExclusiveSettingsIntractionMode);
+ // inform the PermissionResolver that the settings have changed
+ PermissionResolver.settingsChanged(iAppUID, allSettings[i]);
+ }
+ }
+ }
+}