javacommons/security/javasrc/com/nokia/mj/impl/security/midp/authorization/PermissionResolver.java
/*
* 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.util.Vector;
import java.util.Hashtable;
import java.security.Permission;
import com.nokia.mj.impl.utils.Uid;
import com.nokia.mj.impl.utils.Tokenizer;
import com.nokia.mj.impl.utils.exception.InvalidAttributeException;
import com.nokia.mj.impl.utils.InstallerDetailedErrorMessage;
import com.nokia.mj.impl.utils.InstallerErrorMessage;
import com.nokia.mj.impl.utils.OtaStatusCode;
import com.nokia.mj.impl.security.midp.common.PermissionAttribute;
import com.nokia.mj.impl.security.midp.common.PolicyBasedPermission;
import com.nokia.mj.impl.security.midp.common.PolicyBasedPermissionImpl;
import com.nokia.mj.impl.security.midp.common.UserSecuritySettings;
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.security.utils.Logger;
/**
* Permission resolver: it resolves a list of permissions against another list
* of permissions, returning the list of permissions which resolved the
* permissions. Resolving means callint the implies method of Permission
* objects
*/
public final class PermissionResolver
{
/*
* Cache for Permission objects
*/
// Add synchronization for access to these hashtables
private static Hashtable policyPermissionInstances = new Hashtable();
private static Hashtable grantedPermissionInstances = new Hashtable();
public static Vector resolvePermissions(
Uid msUID,
PermissionAttribute[] requestedPermissions,
PolicyBasedPermission[] policyPermissions)
{
if (requestedPermissions == null)
{
return null;
}
Vector resolvedPermissions = new Vector();
for (int i=0; i<requestedPermissions.length; i++)
{
if (requestedPermissions[i].isLegacyAttribute())
{
Vector legacyPermissions = resolveLegacyPermission(requestedPermissions[i],
policyPermissions);
// add legacyPermissions into resolved permissions
// Is it possible to provide the vector to resolveLegacyPermission method which will fill it?
if (legacyPermissions != null && legacyPermissions.size() > 0)
{
for (int j=0; j<legacyPermissions.size(); j++)
{
resolvedPermissions.addElement(
legacyPermissions.elementAt(j));
}
}
else if (requestedPermissions[i].getImportance()
== PermissionAttribute.MANDATORY_PERMISSION)
{
Logger.logError("Permission " + requestedPermissions[i].getName() + " not supported");
throw new InvalidAttributeException(
InstallerErrorMessage.INST_CORRUPT_PKG,
null, /* no params for short msg */
InstallerDetailedErrorMessage.ATTR_UNSUPPORTED,
new String[] {requestedPermissions[i].getAttributeName()},
OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
}
continue;
}
try
{
Permission p = (Permission)ClassInstantiator.newInstance(
requestedPermissions[i].getName(),
requestedPermissions[i].getTarget(),
requestedPermissions[i].getActionList());
Vector resolvedPermissionSet = resolvePermission(
msUID, p, policyPermissions);
if (resolvedPermissionSet != null)
{
if (identicalSettings(resolvedPermissionSet))
{
PolicyBasedPermission rPerm = (PolicyBasedPermission)
resolvedPermissionSet.elementAt(0);
if (rPerm.getUserSecuritySettings() == null)
{
resolvedPermissions.addElement(
new PolicyBasedPermissionImpl(
requestedPermissions[i].getName(),
requestedPermissions[i].getTarget(),
requestedPermissions[i].getActionList(),
rPerm.getType()));
}
else
{
resolvedPermissions.addElement(
new PolicyBasedPermissionImpl(
requestedPermissions[i].getName(),
requestedPermissions[i].getTarget(),
requestedPermissions[i].getActionList(),
rPerm.getUserSecuritySettings()));
}
}
else
{
for (int j=0; j<resolvedPermissionSet.size(); j++)
{
resolvedPermissions.addElement(
resolvedPermissionSet.elementAt(j));
}
}
}
else
{
// the permission was not resovled
if (requestedPermissions[i].getImportance()
== PermissionAttribute.MANDATORY_PERMISSION)
{
Logger.logError("Permission " + requestedPermissions[i].getName() + " not supported");
throw new InvalidAttributeException(
InstallerErrorMessage.INST_CORRUPT_PKG,
null, /* no params for short msg */
InstallerDetailedErrorMessage.ATTR_UNSUPPORTED,
new String[] {requestedPermissions[i].getAttributeName()},
OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
}
}
}
catch (InstantiationException e)
{
if (requestedPermissions[i].getImportance()
== PermissionAttribute.MANDATORY_PERMISSION)
{
Logger.logError("Permission " + requestedPermissions[i].getName() + " not supported");
throw new InvalidAttributeException(
InstallerErrorMessage.INST_CORRUPT_PKG,
null, /* no params for short msg */
InstallerDetailedErrorMessage.ATTR_UNSUPPORTED,
new String[] {requestedPermissions[i].getAttributeName()},
OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
}
// ignore, since the permission was optional
}
}
if (resolvedPermissions.size() == 0)
{
return null;
}
return resolvedPermissions;
}
public static Vector resolvePermission(
StorageSession aStorageSession,
Uid msUID,
Permission requestedPermission)
{
return resolvePermission(requestedPermission,
getGrantedPermissionInstances(aStorageSession, msUID));
}
/**
* Indication that certain settings have changed. This is implemented
* so that the new settings are updated into the cache
*/
// Add synchronization
static void settingsChanged(Uid msUID, UserSecuritySettings newSettings)
{
Vector oldPermissionInstancesAndSettings =
(Vector)grantedPermissionInstances.remove(msUID);
if (oldPermissionInstancesAndSettings != null)
{
Vector newPermissionInstancesAndSettings = new Vector();
for (int i=0; i < oldPermissionInstancesAndSettings.size(); i++)
{
PermisionInstanceAndSettings p = (PermisionInstanceAndSettings)
oldPermissionInstancesAndSettings.elementAt(i);
if (p.getSettings() != null && p.getSettings().getName()
.equals(newSettings.getName()))
{
// add new settings
newPermissionInstancesAndSettings.addElement(
new PermisionInstanceAndSettings(
p.getPermissionInstance(),
p.getType(),
newSettings));
}
else
{
// keep the old settings
newPermissionInstancesAndSettings.addElement(p);
}
}
grantedPermissionInstances.put(msUID,
newPermissionInstancesAndSettings);
}
}
private static Vector resolvePermission(
Permission requestedPermission,
Vector permissionInstances)
{
if (permissionInstances == null
|| requestedPermission == null)
{
return null;
}
Vector resolvedPermissions = new Vector();
// stage 1: try the simple permissions (simple permission = permission with single action)
for (int i=0; i<permissionInstances.size(); i++)
{
PermisionInstanceAndSettings p =
(PermisionInstanceAndSettings)permissionInstances
.elementAt(i);
Object policyPermission = p.getPermissionInstance();
if (policyPermission.getClass().isInstance(requestedPermission)
&& ((Permission)policyPermission).implies(requestedPermission))
{
resolvedPermissions.addElement(
getResolvedPermission(
requestedPermission,
policyPermission,
p.getType(),
p.getSettings(),
requestedPermission.getClass().getName(),
requestedPermission.getName(),
requestedPermission.getActions()));
return resolvedPermissions;
}
}
// stage 2: try the requested complex permissions (complex permission = permission with multiple actions)
String[] actions = Tokenizer.split(requestedPermission.getActions(),
",");
if (actions != null && actions.length > 0)
{
for (int i=0; i<actions.length; i++)
{
boolean permissionResolved = false;
try
{
Permission p1 = (Permission)ClassInstantiator.newInstance(
requestedPermission.getClass().getName(),
requestedPermission.getName(), actions[i]);
for (int j=0; j<permissionInstances.size(); j++)
{
PermisionInstanceAndSettings p =
(PermisionInstanceAndSettings)permissionInstances
.elementAt(j);
Object policyPermission = p.getPermissionInstance();
if (policyPermission.getClass().isInstance(p1)
&& ((Permission)policyPermission).implies(p1))
{
permissionResolved = true;
// add the permission to the result only of not found among the existing ones
PolicyBasedPermissionImpl permission1 =
getResolvedPermission(requestedPermission,
policyPermission,
p.getType(),
p.getSettings(),
requestedPermission.getClass().getName(),
requestedPermission.getName(),
actions[i]);
if (permission1.getActionList() == null
|| permission1.getActionList().length() == 0)
{
resolvedPermissions.addElement(permission1);
continue;
}
UserSecuritySettings settings1 = permission1.getUserSecuritySettings();
boolean found = false;
for (int k=0; k<resolvedPermissions.size(); k++)
{
PolicyBasedPermissionImpl permission2 =
(PolicyBasedPermissionImpl)(resolvedPermissions.elementAt(k));
if (permission2.getActionList() != null
&& permission2.getActionList().length() > 0)
{
UserSecuritySettings settings2 =
permission2.getUserSecuritySettings();
// group resolve permissions by name and settings
if (permission1.getClass().getName().equals(permission2.getClass().getName())
&& ((permission1.getName() != null && permission2.getName() != null
&& permission1.getName().equals(permission2.getName()))
|| (permission1.getName() == null && permission2.getName() == null))
&& ((settings1 != null && settings2 != null && settings1.equals(settings2))
|| (settings1 == null && settings2 == null)))
{
// replace element at position k with another one having
// the combined actions
resolvedPermissions.setElementAt(getResolvedPermission(
permission1.getPromptDetails(),
p.getType(),
p.getSettings(),
requestedPermission.getClass().getName(),
requestedPermission.getName(),
permission2.getActionList() + "," + permission1.getActionList()),
k);
found = true;
break;
}
}
}
if (!found)
{
resolvedPermissions.addElement(permission1);
}
break;
}
}
}
catch (InstantiationException e)
{
// ignore it
}
if (!permissionResolved)
{
resolvedPermissions.removeAllElements();
break;
}
}
if (resolvedPermissions.size() > 0)
{
return resolvedPermissions;
}
}
// stage 3: try the granted complex permissions (complex permission = permission with multiple actions)
// - step 1: group permissions having same name, target and settings
// into a list of complex permissions (= permissions with
// same name, target and settings but with the composite
// action (comma separated list of individual actions)
// - step 2: try to resolve the requested permission against the
// list of complet permissions
Vector tmp = new Vector();
for (int i=0; i<permissionInstances.size(); i++)
{
tmp.addElement(permissionInstances.elementAt(i));
}
while (tmp.size() > 0)
{
PermisionInstanceAndSettings instance1 =
(PermisionInstanceAndSettings)tmp.elementAt(0);
tmp.removeElementAt(0);
Permission permission1 = (Permission)instance1.getPermissionInstance();
int type = instance1.getType();
UserSecuritySettings settings1 = instance1.getSettings();
String compositeAction = "";
// put the individual actions into a vector so that the composite
// action is made only by unique actions (duplicates are discarded)
Vector uniqueActions = new Vector();
int i=0;
while (i<tmp.size())
{
PermisionInstanceAndSettings instance2 =
(PermisionInstanceAndSettings)tmp.elementAt(i);
Permission permission2 = (Permission)instance2.getPermissionInstance();
UserSecuritySettings settings2 = instance2.getSettings();
if (permission1.getClass().getName().equals(permission2.getClass().getName())
&& ((permission1.getName() != null && permission2.getName() != null
&& permission1.getName().equals(permission2.getName()))
|| (permission1.getName() == null && permission2.getName() == null))
&& ((settings1 != null && settings2 != null && settings1.equals(settings2))
|| (settings1 == null && settings2 == null)))
{
tmp.removeElementAt(i);
if (permission1.getActions() != null && permission1.getActions().length() > 0)
{
if (!uniqueActions.contains(permission1.getActions()))
{
if (compositeAction.length() > 0)
{
compositeAction += ",";
}
compositeAction += permission1.getActions();
uniqueActions.addElement(permission1.getActions());
}
}
if (permission2.getActions() != null && permission2.getActions().length() > 0)
{
if (!uniqueActions.contains(permission2.getActions()))
{
if (compositeAction.length() > 0)
{
compositeAction += ",";
}
compositeAction += permission2.getActions();
uniqueActions.addElement(permission2.getActions());
}
}
}
else
{
i++;
}
}
if (compositeAction.length() > 0 && compositeAction.indexOf(',') != -1)
{
try
{
Permission perm = (Permission)ClassInstantiator.newInstance(
permission1.getClass().getName(),
permission1.getName(),
compositeAction);
if (perm.getClass().isInstance(requestedPermission)
&& perm.implies(requestedPermission))
{
resolvedPermissions.addElement(
getResolvedPermission(
requestedPermission,
permission1,
type,
settings1,
requestedPermission.getClass().getName(),
requestedPermission.getName(),
requestedPermission.getActions()));
return resolvedPermissions;
}
}
catch (InstantiationException ex) {}
}
}
if (resolvedPermissions.size() == 0)
{
return null;
}
return resolvedPermissions;
}
private static Vector resolvePermission(
Uid msUID,
Permission requestedPermission,
PolicyBasedPermission[] policyPermissions)
{
Vector permissionInstances = getPolicyPermissionInstances(
msUID, policyPermissions);
return resolvePermission(requestedPermission, permissionInstances);
}
private static PolicyBasedPermissionImpl getResolvedPermission(
PermissionBase securityPromptDetails,
int type,
UserSecuritySettings userSettings,
String permissionName,
String targetName,
String actionList)
{
PermissionBase securityPromptDetails2 = securityPromptDetails;
if (securityPromptDetails != null
&& (!PermissionBase.matchActions(securityPromptDetails.getActions(),actionList)
|| !PermissionBase.matchActions(actionList, securityPromptDetails.getActions())))
{
// the new instance is created only if the actions are different
try
{
securityPromptDetails2 = (PermissionBase)ClassInstantiator
.newInstance(securityPromptDetails.getClass().getName(),
securityPromptDetails.getName(),
actionList);
}
catch (InstantiationException e2)
{
// ignore it (no details)
}
}
return new PolicyBasedPermissionImpl(
permissionName,
targetName,
actionList,
type,
userSettings,
securityPromptDetails2);
}
private static PolicyBasedPermissionImpl getResolvedPermission(
Permission requestedPermission,
Object policyPermission,
int type,
UserSecuritySettings userSettings,
String permissionName,
String targetName,
String actionList)
{
PermissionBase securityPromptDetails = null;
if (requestedPermission instanceof PermissionBase)
{
securityPromptDetails = (PermissionBase)requestedPermission;
}
else if (policyPermission instanceof PermissionBase)
{
try
{
securityPromptDetails = (PermissionBase)ClassInstantiator
.newInstance(policyPermission.getClass().getName(),
requestedPermission.getName(),
requestedPermission.getActions());
}
catch (InstantiationException e2)
{
// ignore it (no details)
}
}
return new PolicyBasedPermissionImpl(
permissionName,
targetName,
actionList,
type,
userSettings,
securityPromptDetails);
}
private static Vector getPolicyPermissionInstances(Uid msUID, PolicyBasedPermission[] policyPermissions)
{
// try retrieving the policy permissions from cache
Vector policyPermissionInstancesAndSettings =
(Vector)policyPermissionInstances.get(msUID);
if (policyPermissionInstancesAndSettings != null)
{
return policyPermissionInstancesAndSettings;
}
// if the policy permissions are not in cache, then build it
// from policy permissions
policyPermissionInstancesAndSettings = new Vector();
if (policyPermissions == null)
{
return null;
}
for (int i=0; i<policyPermissions.length; i++)
{
try
{
Object p = ClassInstantiator.newInstance(
policyPermissions[i].getName(),
policyPermissions[i].getTarget(),
policyPermissions[i].getActionList());
policyPermissionInstancesAndSettings.addElement(
new PermisionInstanceAndSettings(p,
policyPermissions[i].getType(),
policyPermissions[i].getUserSecuritySettings()));
}
catch (InstantiationException e)
{
// This should not be leaked outside
Logger.logError("getPolicyPermissionInstances failed: " + e.toString());
}
}
policyPermissionInstances.put(msUID,
policyPermissionInstancesAndSettings);
return policyPermissionInstancesAndSettings;
}
private static Vector getGrantedPermissionInstances(StorageSession aStorageSession, Uid msUID)
{
// try retrieving the policy permissions from cache
Vector grantedPermissionInstancesAndSettings =
(Vector)grantedPermissionInstances.get(msUID);
if (grantedPermissionInstancesAndSettings != null)
{
return grantedPermissionInstancesAndSettings;
}
// if the granted permissions are not in cache, then retrieve them
// from storage
grantedPermissionInstancesAndSettings = new Vector();
SecurityStorage storage = new SecurityStorage(aStorageSession);
Vector grantedPermissions =
storage.readGrantedPermissions(msUID);
if (grantedPermissions == null)
{
return null;
}
for (int i=0; i<grantedPermissions.size(); i++)
{
try
{
PolicyBasedPermission grantedPermission =
(PolicyBasedPermission)grantedPermissions.elementAt(i);
Object p = ClassInstantiator.newInstance(
grantedPermission.getName(),
grantedPermission.getTarget(),
grantedPermission.getActionList());
grantedPermissionInstancesAndSettings.addElement(
new PermisionInstanceAndSettings(p,
grantedPermission.getType(),
grantedPermission.getUserSecuritySettings()));
}
catch (InstantiationException e)
{
// This should not be leaked outside
}
}
grantedPermissionInstances.put(msUID,
grantedPermissionInstancesAndSettings);
return grantedPermissionInstancesAndSettings;
}
private static boolean identicalSettings(
Vector permissions)
{
UserSecuritySettings settings = ((PolicyBasedPermission)permissions
.elementAt(0)).getUserSecuritySettings();
for (int i=1; i<permissions.size(); i++)
{
PolicyBasedPermission p = (PolicyBasedPermission)permissions
.elementAt(i);
if ((settings == null
&& p.getUserSecuritySettings() != null)
|| !settings.equals(p.getUserSecuritySettings()))
{
return false;
}
}
return true;
}
// if requested permission is a legacy one, then handle the wildcards:
// - if the name is null -> grant all the permissions from the policy
// - if name is not null -> then grant the permissions from policy with the same name
// - if target is null -> take the target from the policy permission, otherwise take the target of the requested permission
// - if actionList is null -> take the actionList from the policy permission, otherwise take the actionList of the requested
// permission if it matches the actionList from the policy
private static Vector resolveLegacyPermission(PermissionAttribute legacyPermission, PolicyBasedPermission[] policyPermissions)
{
if (policyPermissions == null)
{
return null;
}
Vector resolvedPermissions = new Vector();
if (legacyPermission.getName() == null)
{
if (policyPermissions == null)
{
return null;
}
resolvedPermissions = new Vector();
for (int i=0; i<policyPermissions.length; i++)
{
resolvedPermissions.addElement(
new PolicyBasedPermissionImpl(
policyPermissions[i].getName(),
policyPermissions[i].getTarget(),
policyPermissions[i].getActionList(),
policyPermissions[i].getUserSecuritySettings()));
}
}
else
{
// return permissions from policy with same name
for (int i=0; i<policyPermissions.length; i++)
{
if (legacyPermission.getName().equals(
policyPermissions[i].getName()))
{
// choose the target: if the target does not include wildcards,
// then there must be an exact match between the requested
// permission and the policy permission
String target = legacyPermission.getTarget();
if (target != null
&& target.indexOf("*") == -1
&& !target.equals(policyPermissions[i].getTarget()))
{
continue;
}
// choose the action
String actionList = legacyPermission.getActionList();
if (actionList == null)
{
resolvedPermissions.addElement(
new PolicyBasedPermissionImpl(
policyPermissions[i].getName(),
policyPermissions[i].getTarget(),
policyPermissions[i].getActionList(),
policyPermissions[i].getUserSecuritySettings()));
}
else
{
if (PermissionBase.matchActions(actionList,
policyPermissions[i].getActionList()))
{
resolvedPermissions.addElement(
new PolicyBasedPermissionImpl(
policyPermissions[i].getName(),
policyPermissions[i].getTarget(),
actionList,
policyPermissions[i].getUserSecuritySettings()));
}
}
}
}
}
return resolvedPermissions;
}
private static class PermisionInstanceAndSettings
{
private Object permissionObject;
private int type;
private UserSecuritySettings settings;
public PermisionInstanceAndSettings(Object permissionObject, int type, UserSecuritySettings settings)
{
this.permissionObject = permissionObject;
this.type = type;
this.settings = settings;
}
public Object getPermissionInstance()
{
return permissionObject;
}
public UserSecuritySettings getSettings()
{
return settings;
}
public int getType()
{
return type;
}
}
}