| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.felix.framework.security.condpermadmin; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.math.BigInteger; |
| import java.net.URL; |
| import java.security.AccessControlContext; |
| import java.security.InvalidKeyException; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.security.Permission; |
| import java.security.Principal; |
| import java.security.ProtectionDomain; |
| import java.security.PublicKey; |
| import java.security.SignatureException; |
| import java.security.cert.X509Certificate; |
| import java.util.AbstractSet; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Date; |
| import java.util.Dictionary; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| import java.util.Map.Entry; |
| |
| import org.apache.felix.framework.BundleProtectionDomain; |
| import org.apache.felix.framework.security.permissionadmin.PermissionAdminImpl; |
| import org.apache.felix.framework.security.util.Conditions; |
| import org.apache.felix.framework.security.util.LocalPermissions; |
| import org.apache.felix.framework.security.util.Permissions; |
| import org.apache.felix.framework.security.util.PropertiesCache; |
| import org.apache.felix.framework.util.manifestparser.R4Library; |
| |
| /* |
| import org.apache.felix.moduleloader.ICapability; |
| import org.apache.felix.moduleloader.IContent; |
| import org.apache.felix.moduleloader.IModule; |
| import org.apache.felix.moduleloader.IRequirement; |
| import org.apache.felix.moduleloader.IWire; |
| */ |
| import org.apache.felix.framework.capabilityset.Capability; |
| import org.apache.felix.framework.capabilityset.Requirement; |
| import org.apache.felix.framework.resolver.Content; |
| import org.apache.felix.framework.resolver.Module; |
| import org.apache.felix.framework.resolver.Wire; |
| |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.framework.Version; |
| import org.osgi.service.condpermadmin.ConditionInfo; |
| import org.osgi.service.condpermadmin.ConditionalPermissionAdmin; |
| import org.osgi.service.condpermadmin.ConditionalPermissionInfo; |
| import org.osgi.service.condpermadmin.ConditionalPermissionUpdate; |
| import org.osgi.service.permissionadmin.PermissionInfo; |
| |
| /** |
| * An implementation of the ConditionalPermissionAdmin service that doesn't need |
| * to have a framework specific security manager set. It use the DomainGripper |
| * to know what bundleprotectiondomains are expected. |
| */ |
| public final class ConditionalPermissionAdminImpl implements |
| ConditionalPermissionAdmin |
| { |
| private static class OrderedHashMap extends HashMap |
| { |
| private final List m_order = new ArrayList(); |
| |
| public Object put(Object key, Object value) |
| { |
| Object result = super.put(key, value); |
| if (result != value) |
| { |
| m_order.remove(key); |
| m_order.add(key); |
| } |
| return result; |
| }; |
| |
| public void putAll(Map map) |
| { |
| for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) |
| { |
| Entry entry = (Entry) iter.next(); |
| put(entry.getKey(), entry.getValue()); |
| } |
| }; |
| |
| public Set keySet() |
| { |
| return new AbstractSet() |
| { |
| public Iterator iterator() |
| { |
| return m_order.iterator(); |
| } |
| |
| public int size() |
| { |
| return m_order.size(); |
| } |
| |
| }; |
| }; |
| |
| public Set entrySet() |
| { |
| return new AbstractSet() |
| { |
| |
| public Iterator iterator() |
| { |
| return new Iterator() |
| { |
| Iterator m_iter = m_order.iterator(); |
| |
| public boolean hasNext() |
| { |
| return m_iter.hasNext(); |
| } |
| |
| public Object next() |
| { |
| final Object key = m_iter.next(); |
| return new Entry() |
| { |
| |
| public Object getKey() |
| { |
| return key; |
| } |
| |
| public Object getValue() |
| { |
| return get(key); |
| } |
| |
| public Object setValue(Object arg0) |
| { |
| throw new IllegalStateException( |
| "Not Implemented"); |
| } |
| }; |
| } |
| |
| public void remove() |
| { |
| throw new IllegalStateException("Not Implemented"); |
| } |
| |
| }; |
| } |
| |
| public int size() |
| { |
| return m_order.size(); |
| } |
| |
| }; |
| }; |
| |
| public Collection values() |
| { |
| List result = new ArrayList(); |
| for (Iterator iter = m_order.iterator(); iter.hasNext();) |
| { |
| result.add(super.get(iter.next())); |
| } |
| return result; |
| }; |
| |
| public Object remove(Object key) |
| { |
| Object result = super.remove(key); |
| if (result != null) |
| { |
| m_order.remove(key); |
| } |
| return result; |
| }; |
| |
| public void clear() |
| { |
| super.clear(); |
| m_order.clear(); |
| }; |
| }; |
| |
| private static final ConditionInfo[] EMPTY_CONDITION_INFO = new ConditionInfo[0]; |
| private static final PermissionInfo[] EMPTY_PERMISSION_INFO = new PermissionInfo[0]; |
| private final Map m_condPermInfos = new OrderedHashMap(); |
| private final PropertiesCache m_propertiesCache; |
| private final Permissions m_permissions; |
| private final Conditions m_conditions; |
| private final LocalPermissions m_localPermissions; |
| private final PermissionAdminImpl m_pai; |
| |
| public ConditionalPermissionAdminImpl(Permissions permissions, |
| Conditions condtions, LocalPermissions localPermissions, |
| PropertiesCache cache, PermissionAdminImpl pai) throws IOException |
| { |
| m_propertiesCache = cache; |
| m_permissions = permissions; |
| m_conditions = condtions; |
| m_localPermissions = localPermissions; |
| Map old = new OrderedHashMap(); |
| // Now try to restore the cache. |
| m_propertiesCache.read(ConditionalPermissionInfoImpl.class, old); |
| for (Iterator iter = old.entrySet().iterator(); iter.hasNext();) |
| { |
| Entry entry = (Entry) iter.next(); |
| String name = (String) entry.getKey(); |
| ConditionalPermissionInfoImpl cpi = ((ConditionalPermissionInfoImpl) entry |
| .getValue()); |
| m_condPermInfos.put(name, new ConditionalPermissionInfoImpl(name, |
| cpi._getConditionInfos(), cpi._getPermissionInfos(), this, cpi |
| .isAllow())); |
| } |
| m_pai = pai; |
| } |
| |
| public ConditionalPermissionInfo addConditionalPermissionInfo( |
| ConditionInfo[] conditions, PermissionInfo[] permissions) |
| { |
| Object sm = System.getSecurityManager(); |
| if (sm != null) |
| { |
| ((SecurityManager) sm).checkPermission(Permissions.ALL_PERMISSION); |
| } |
| ConditionalPermissionInfoImpl result = new ConditionalPermissionInfoImpl( |
| notNull(conditions), notNull(permissions), this, true); |
| |
| return write(result.getName(), result); |
| } |
| |
| ConditionalPermissionInfoImpl write(String name, |
| ConditionalPermissionInfoImpl cpi) |
| { |
| synchronized (m_propertiesCache) |
| { |
| Map tmp = null; |
| |
| synchronized (m_condPermInfos) |
| { |
| tmp = new OrderedHashMap(); |
| tmp.putAll(m_condPermInfos); |
| |
| if ((name != null) && (cpi != null)) |
| { |
| m_condPermInfos.put(name, cpi); |
| } |
| else if (name != null) |
| { |
| m_condPermInfos.remove(name); |
| } |
| else |
| { |
| tmp = null; |
| } |
| } |
| |
| try |
| { |
| m_propertiesCache.write(m_condPermInfos); |
| } |
| catch (IOException ex) |
| { |
| synchronized (m_condPermInfos) |
| { |
| if (tmp != null) |
| { |
| m_condPermInfos.clear(); |
| m_condPermInfos.putAll(tmp); |
| } |
| } |
| ex.printStackTrace(); |
| throw new IllegalStateException(ex.getMessage()); |
| } |
| } |
| synchronized (m_condPermInfos) |
| { |
| return (ConditionalPermissionInfoImpl) m_condPermInfos.get(name); |
| } |
| } |
| |
| private static class FakeBundle implements Bundle |
| { |
| private final Map m_certs; |
| |
| public FakeBundle(Map certs) |
| { |
| m_certs = Collections.unmodifiableMap(certs); |
| } |
| |
| public Enumeration findEntries(String arg0, String arg1, boolean arg2) |
| { |
| return null; |
| } |
| |
| public BundleContext getBundleContext() |
| { |
| return null; |
| } |
| |
| public long getBundleId() |
| { |
| return -1; |
| } |
| |
| public URL getEntry(String arg0) |
| { |
| return null; |
| } |
| |
| public Enumeration getEntryPaths(String arg0) |
| { |
| return null; |
| } |
| |
| public Dictionary getHeaders() |
| { |
| return new Hashtable(); |
| } |
| |
| public Dictionary getHeaders(String arg0) |
| { |
| return new Hashtable(); |
| } |
| |
| public long getLastModified() |
| { |
| return 0; |
| } |
| |
| public String getLocation() |
| { |
| return ""; |
| } |
| |
| public ServiceReference[] getRegisteredServices() |
| { |
| return null; |
| } |
| |
| public URL getResource(String arg0) |
| { |
| return null; |
| } |
| |
| public Enumeration getResources(String arg0) throws IOException |
| { |
| return null; |
| } |
| |
| public ServiceReference[] getServicesInUse() |
| { |
| return null; |
| } |
| |
| public Map getSignerCertificates(int arg0) |
| { |
| return m_certs; |
| } |
| |
| public int getState() |
| { |
| return Bundle.UNINSTALLED; |
| } |
| |
| public String getSymbolicName() |
| { |
| return null; |
| } |
| |
| public Version getVersion() |
| { |
| return Version.emptyVersion; |
| } |
| |
| public boolean hasPermission(Object arg0) |
| { |
| return false; |
| } |
| |
| public Class loadClass(String arg0) throws ClassNotFoundException |
| { |
| return null; |
| } |
| |
| public void start() throws BundleException |
| { |
| throw new IllegalStateException(); |
| } |
| |
| public void start(int arg0) throws BundleException |
| { |
| throw new IllegalStateException(); |
| } |
| |
| public void stop() throws BundleException |
| { |
| throw new IllegalStateException(); |
| } |
| |
| public void stop(int arg0) throws BundleException |
| { |
| throw new IllegalStateException(); |
| } |
| |
| public void uninstall() throws BundleException |
| { |
| throw new IllegalStateException(); |
| } |
| |
| public void update() throws BundleException |
| { |
| throw new IllegalStateException(); |
| } |
| |
| public void update(InputStream arg0) throws BundleException |
| { |
| throw new IllegalStateException(); |
| } |
| |
| public boolean equals(Object o) |
| { |
| return this == o; |
| } |
| |
| public int hashCode() |
| { |
| return System.identityHashCode(this); |
| } |
| } |
| |
| private static class FakeCert extends X509Certificate |
| { |
| private final Principal m_principal; |
| |
| public FakeCert(final String principal) |
| { |
| m_principal = new Principal() |
| { |
| public String getName() |
| { |
| return principal; |
| } |
| }; |
| } |
| |
| public void checkValidity() |
| throws java.security.cert.CertificateExpiredException, |
| java.security.cert.CertificateNotYetValidException |
| { |
| |
| } |
| |
| public void checkValidity(Date date) |
| throws java.security.cert.CertificateExpiredException, |
| java.security.cert.CertificateNotYetValidException |
| { |
| } |
| |
| public int getBasicConstraints() |
| { |
| return 0; |
| } |
| |
| public Principal getIssuerDN() |
| { |
| return null; |
| } |
| |
| public boolean[] getIssuerUniqueID() |
| { |
| return null; |
| } |
| |
| public boolean[] getKeyUsage() |
| { |
| return null; |
| } |
| |
| public Date getNotAfter() |
| { |
| return null; |
| } |
| |
| public Date getNotBefore() |
| { |
| return null; |
| } |
| |
| public BigInteger getSerialNumber() |
| { |
| return null; |
| } |
| |
| public String getSigAlgName() |
| { |
| return null; |
| } |
| |
| public String getSigAlgOID() |
| { |
| return null; |
| } |
| |
| public byte[] getSigAlgParams() |
| { |
| return null; |
| } |
| |
| public byte[] getSignature() |
| { |
| return null; |
| } |
| |
| public Principal getSubjectDN() |
| { |
| return m_principal; |
| } |
| |
| public boolean[] getSubjectUniqueID() |
| { |
| return null; |
| } |
| |
| public byte[] getTBSCertificate() |
| throws java.security.cert.CertificateEncodingException |
| { |
| return null; |
| } |
| |
| public int getVersion() |
| { |
| return 0; |
| } |
| |
| public byte[] getEncoded() |
| throws java.security.cert.CertificateEncodingException |
| { |
| return null; |
| } |
| |
| public PublicKey getPublicKey() |
| { |
| return null; |
| } |
| |
| public String toString() |
| { |
| return m_principal.getName(); |
| } |
| |
| public void verify(PublicKey key) |
| throws java.security.cert.CertificateException, |
| NoSuchAlgorithmException, InvalidKeyException, |
| NoSuchProviderException, SignatureException |
| { |
| |
| } |
| |
| public void verify(PublicKey key, String sigProvider) |
| throws java.security.cert.CertificateException, |
| NoSuchAlgorithmException, InvalidKeyException, |
| NoSuchProviderException, SignatureException |
| { |
| |
| } |
| |
| public Set getCriticalExtensionOIDs() |
| { |
| return null; |
| } |
| |
| public byte[] getExtensionValue(String arg0) |
| { |
| return null; |
| } |
| |
| public Set getNonCriticalExtensionOIDs() |
| { |
| return null; |
| } |
| |
| public boolean hasUnsupportedCriticalExtension() |
| { |
| return false; |
| } |
| |
| public boolean equals(Object o) |
| { |
| return this == o; |
| } |
| |
| public int hashCode() |
| { |
| return System.identityHashCode(this); |
| } |
| |
| } |
| |
| public AccessControlContext getAccessControlContext(final String[] signers) |
| { |
| Map certificates = new HashMap(); |
| for (int i = 0; i < signers.length; i++) |
| { |
| StringTokenizer tok = new StringTokenizer(signers[i], ";"); |
| List certsList = new ArrayList(); |
| while (tok.hasMoreTokens()) |
| { |
| certsList.add(tok.nextToken()); |
| } |
| String[] certs = (String[]) certsList.toArray(new String[certsList |
| .size()]); |
| |
| X509Certificate key = new FakeCert(certs[0]); |
| List certList = new ArrayList(); |
| certificates.put(key, certList); |
| certList.add(key); |
| for (int j = 1; j < certs.length; j++) |
| { |
| certList.add(new FakeCert(certs[j])); |
| } |
| } |
| final Bundle fake = new FakeBundle(certificates); |
| ProtectionDomain domain = new ProtectionDomain(null, null) |
| { |
| public boolean implies(Permission permission) |
| { |
| List posts = new ArrayList(); |
| Boolean result = m_pai.hasPermission("", fake, permission, |
| ConditionalPermissionAdminImpl.this, this, null); |
| if (result != null) |
| { |
| return result.booleanValue(); |
| } |
| if (eval(posts, new Module() |
| { |
| |
| public Bundle getBundle() |
| { |
| return fake; |
| } |
| |
| public List<Capability> getCapabilities() |
| { |
| return null; |
| } |
| |
| public Class getClassByDelegation(String arg0) |
| throws ClassNotFoundException |
| { |
| return null; |
| } |
| |
| public Content getContent() |
| { |
| return null; |
| } |
| |
| public int getDeclaredActivationPolicy() |
| { |
| return 0; |
| } |
| |
| public List<Requirement> getDynamicRequirements() |
| { |
| return null; |
| } |
| |
| public URL getEntry(String arg0) |
| { |
| return null; |
| } |
| |
| public Map getHeaders() |
| { |
| return null; |
| } |
| |
| public String getId() |
| { |
| return null; |
| } |
| |
| public InputStream getInputStream(int arg0, String arg1) |
| throws IOException |
| { |
| return null; |
| } |
| |
| public List<R4Library> getNativeLibraries() |
| { |
| return null; |
| } |
| |
| public List<Requirement> getRequirements() |
| { |
| return null; |
| } |
| |
| public URL getResourceByDelegation(String arg0) |
| { |
| return null; |
| } |
| |
| public Enumeration getResourcesByDelegation(String arg0) |
| { |
| return null; |
| } |
| |
| public Object getSecurityContext() |
| { |
| return null; |
| } |
| |
| public String getSymbolicName() |
| { |
| return null; |
| } |
| |
| public Version getVersion() |
| { |
| return null; |
| } |
| |
| public List<Wire> getWires() |
| { |
| return null; |
| } |
| |
| public boolean hasInputStream(int arg0, String arg1) |
| throws IOException |
| { |
| return false; |
| } |
| |
| public boolean isExtension() |
| { |
| return false; |
| } |
| |
| public boolean isResolved() |
| { |
| return false; |
| } |
| |
| public void setSecurityContext(Object arg0) |
| { |
| } |
| |
| public URL getLocalURL(int arg0, String arg1) |
| { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public boolean isRemovalPending() |
| { |
| return false; |
| } |
| }, permission, m_pai)) |
| { |
| if (!posts.isEmpty()) |
| { |
| return m_conditions.evalRecursive(posts); |
| } |
| return true; |
| } |
| return false; |
| } |
| }; |
| return new AccessControlContext(new ProtectionDomain[] { domain }); |
| } |
| |
| public ConditionalPermissionInfo getConditionalPermissionInfo(String name) |
| { |
| if (name == null) |
| { |
| throw new IllegalArgumentException("Name may not be null"); |
| } |
| ConditionalPermissionInfoImpl result = null; |
| |
| synchronized (m_condPermInfos) |
| { |
| result = (ConditionalPermissionInfoImpl) m_condPermInfos.get(name); |
| } |
| |
| if (result == null) |
| { |
| result = new ConditionalPermissionInfoImpl(this, name, true); |
| |
| result = write(result.getName(), result); |
| } |
| |
| return result; |
| } |
| |
| public Enumeration getConditionalPermissionInfos() |
| { |
| synchronized (m_condPermInfos) |
| { |
| return Collections.enumeration(new ArrayList(m_condPermInfos |
| .values())); |
| } |
| } |
| |
| public ConditionalPermissionInfo setConditionalPermissionInfo(String name, |
| ConditionInfo[] conditions, PermissionInfo[] permissions) |
| { |
| Object sm = System.getSecurityManager(); |
| if (sm != null) |
| { |
| ((SecurityManager) sm).checkPermission(Permissions.ALL_PERMISSION); |
| } |
| |
| ConditionalPermissionInfoImpl result = null; |
| conditions = notNull(conditions); |
| permissions = notNull(permissions); |
| |
| if (name != null) |
| { |
| synchronized (m_condPermInfos) |
| { |
| result = (ConditionalPermissionInfoImpl) m_condPermInfos |
| .get(name); |
| |
| if (result == null) |
| { |
| result = new ConditionalPermissionInfoImpl(name, |
| conditions, permissions, this, true); |
| } |
| else |
| { |
| result.setConditionsAndPermissions(conditions, permissions); |
| } |
| } |
| } |
| else |
| { |
| result = new ConditionalPermissionInfoImpl(conditions, permissions, |
| this, true); |
| } |
| |
| return write(result.getName(), result); |
| } |
| |
| private PermissionInfo[] notNull(PermissionInfo[] permissions) |
| { |
| if (permissions == null) |
| { |
| return ConditionalPermissionInfoImpl.PERMISSION_INFO; |
| } |
| return (PermissionInfo[]) notNull((Object[]) permissions).toArray( |
| EMPTY_PERMISSION_INFO); |
| } |
| |
| private ConditionInfo[] notNull(ConditionInfo[] conditions) |
| { |
| if (conditions == null) |
| { |
| return ConditionalPermissionInfoImpl.CONDITION_INFO; |
| } |
| return (ConditionInfo[]) notNull((Object[]) conditions).toArray( |
| EMPTY_CONDITION_INFO); |
| } |
| |
| private List notNull(Object[] elements) |
| { |
| List result = new ArrayList(); |
| |
| for (int i = 0; i < elements.length; i++) |
| { |
| if (elements[i] != null) |
| { |
| result.add(elements[i]); |
| } |
| } |
| |
| return result; |
| } |
| |
| // The thread local stack used to keep track of bundle protection domains we |
| // still expect to see. |
| private final ThreadLocal m_stack = new ThreadLocal(); |
| |
| /** |
| * This method does the actual permission check. If it is not a direct check |
| * it will try to determine the other bundle domains that will follow |
| * automatically in case this is the first check in one permission check. If |
| * not then it will keep track of which domains we have already see. While |
| * it keeps track it builds up a list of postponed tuples which it will |
| * evaluate at the last domain. See the core spec 9.5.1 and following for a |
| * general description. |
| * |
| * @param felixBundle |
| * the bundle in question. |
| * @param loader |
| * the content loader of the bundle to get access to the jar to |
| * check for local permissions. |
| * @param root |
| * the bundle id. |
| * @param signers |
| * the signers (this is to support the ACC based on signers) |
| * @param pd |
| * the bundle protection domain |
| * @param permission |
| * the permission currently checked |
| * @param direct |
| * whether this is a direct check or not. direct check will not |
| * expect any further bundle domains on the stack |
| * @return true in case the permission is granted or there are postponed |
| * tuples false if not. Again, see the spec for more explanations. |
| */ |
| public boolean hasPermission(Module module, Content content, |
| ProtectionDomain pd, Permission permission, boolean direct, Object admin) |
| { |
| // System.out.println(felixBundle + "-" + permission); |
| List domains = null; |
| List tuples = null; |
| Object[] entry = null; |
| // first see whether this is the normal case (the special case is for |
| // the ACC based on signers). |
| // In case of a direct call we don't need to look for other pds |
| if (direct) |
| { |
| domains = new ArrayList(); |
| tuples = new ArrayList(); |
| domains.add(pd); |
| } |
| else |
| { |
| // Get the other pds from the stck |
| entry = (Object[]) m_stack.get(); |
| |
| // if there are none then get them from the gripper |
| if (entry == null) |
| { |
| entry = new Object[] { new ArrayList(DomainGripper.grab()), |
| new ArrayList() }; |
| } |
| else |
| { |
| m_stack.set(null); |
| } |
| |
| domains = (List) entry[0]; |
| tuples = (List) entry[1]; |
| if (!domains.contains(pd)) |
| { |
| // We have been called directly without the direct flag |
| domains.clear(); |
| domains.add(pd); |
| } |
| } |
| |
| // check the local permissions. they need to all the permission if there |
| // are any |
| if (!impliesLocal(module.getBundle(), content, permission)) |
| { |
| return false; |
| } |
| |
| List posts = new ArrayList(); |
| |
| boolean result = eval(posts, module, permission, admin); |
| |
| domains.remove(pd); |
| |
| // We postponed tuples |
| if (!posts.isEmpty()) |
| { |
| tuples.add(posts); |
| } |
| |
| // Are we at the end or this was a direct call? |
| if (domains.isEmpty()) |
| { |
| m_stack.set(null); |
| // Now eval the postponed tupels. if the previous eval did return |
| // false |
| // tuples will be empty so we don't return from here. |
| if (!tuples.isEmpty()) |
| { |
| return m_conditions.evalRecursive(tuples); |
| } |
| } |
| else |
| { |
| // this is to support recursive permission checks. In case we |
| // trigger |
| // a permission check while eval the stack is null until this point |
| m_stack.set(entry); |
| } |
| |
| return result; |
| } |
| |
| public boolean impliesLocal(Bundle felixBundle, Content content, |
| Permission permission) |
| { |
| return m_localPermissions.implies(content, felixBundle, permission); |
| } |
| |
| public boolean isEmpty() |
| { |
| synchronized (m_condPermInfos) |
| { |
| return m_condPermInfos.isEmpty(); |
| } |
| } |
| |
| // we need to find all conditions that apply and then check whether they |
| // de note the permission in question unless the conditions are postponed |
| // then we make sure their permissions imply the permission and add them |
| // to the list of posts. Return true in case we pass or have posts |
| // else falls and clear the posts first. |
| private boolean eval(List posts, Module module, Permission permission, |
| Object admin) |
| { |
| List condPermInfos = null; |
| |
| synchronized (m_condPermInfos) |
| { |
| if (isEmpty() && (admin == null)) |
| { |
| return true; |
| } |
| condPermInfos = new ArrayList(m_condPermInfos.values()); |
| } |
| |
| // Check for implicit permissions like access to file area |
| if (m_permissions.getPermissions( |
| m_permissions.getImplicit(module.getBundle())).implies(permission, |
| module.getBundle())) |
| { |
| return true; |
| } |
| List pls = new ArrayList(); |
| // now do the real thing |
| for (Iterator iter = condPermInfos.iterator(); iter.hasNext();) |
| { |
| ConditionalPermissionInfoImpl cpi = (ConditionalPermissionInfoImpl) iter |
| .next(); |
| |
| ConditionInfo[] conditions = cpi._getConditionInfos(); |
| |
| List currentPosts = new ArrayList(); |
| |
| Conditions conds = m_conditions.getConditions(module, conditions); |
| if (!conds.isSatisfied(currentPosts, m_permissions |
| .getPermissions(cpi._getPermissionInfos()), permission)) |
| { |
| continue; |
| } |
| |
| if (!m_permissions.getPermissions(cpi._getPermissionInfos()) |
| .implies(permission, null)) |
| { |
| continue; |
| } |
| |
| if (currentPosts.isEmpty()) |
| { |
| pls.add(new Object[] { cpi, null }); |
| break; |
| } |
| pls.add(new Object[] { cpi, currentPosts, conds }); |
| } |
| while (pls.size() > 1) |
| { |
| if (!((ConditionalPermissionInfoImpl) ((Object[]) pls.get(pls |
| .size() - 1))[0]).isAllow()) |
| { |
| pls.remove(pls.size() - 1); |
| } |
| else |
| { |
| break; |
| } |
| } |
| if (pls.size() == 1) |
| { |
| if (((Object[]) pls.get(0))[1] != null) |
| { |
| posts.add(pls.get(0)); |
| } |
| return ((ConditionalPermissionInfoImpl) ((Object[]) pls.get(0))[0]) |
| .isAllow(); |
| } |
| for (Iterator iter = pls.iterator(); iter.hasNext();) |
| { |
| posts.add(iter.next()); |
| } |
| return !posts.isEmpty(); |
| } |
| |
| public ConditionalPermissionInfo newConditionalPermissionInfo( |
| String encodedConditionalPermissionInfo) |
| { |
| return new ConditionalPermissionInfoImpl( |
| encodedConditionalPermissionInfo); |
| } |
| |
| public ConditionalPermissionInfo newConditionalPermissionInfo(String name, |
| ConditionInfo[] conditions, PermissionInfo[] permissions, String access) |
| { |
| return new ConditionalPermissionInfoImpl(name, conditions, permissions, |
| ConditionalPermissionAdminImpl.this, access |
| .equals(ConditionalPermissionInfo.ALLOW)); |
| } |
| |
| public ConditionalPermissionUpdate newConditionalPermissionUpdate() |
| { |
| return new ConditionalPermissionUpdate() |
| { |
| List current = null; |
| List out = null; |
| { |
| synchronized (m_condPermInfos) |
| { |
| current = new ArrayList(m_condPermInfos.values()); |
| out = new ArrayList(m_condPermInfos.values()); |
| } |
| } |
| |
| public boolean commit() |
| { |
| synchronized (m_condPermInfos) |
| { |
| if (current.equals(new ArrayList(m_condPermInfos.values()))) |
| { |
| m_condPermInfos.clear(); |
| write(null, null); |
| for (Iterator iter = out.iterator(); iter.hasNext();) |
| { |
| ConditionalPermissionInfoImpl cpii = (ConditionalPermissionInfoImpl) iter |
| .next(); |
| write(cpii.getName(), cpii); |
| } |
| } |
| else |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public List getConditionalPermissionInfos() |
| { |
| return out; |
| } |
| }; |
| } |
| |
| public boolean handlePAHandle(BundleProtectionDomain pd) |
| { |
| Object[] entry = (Object[]) m_stack.get(); |
| |
| if (entry == null) |
| { |
| entry = new Object[] { new ArrayList(DomainGripper.grab()), |
| new ArrayList() }; |
| } |
| |
| ((List) entry[0]).remove(pd); |
| if (((List) entry[0]).isEmpty()) |
| { |
| m_stack.set(null); |
| if (!((List) entry[1]).isEmpty()) |
| { |
| return m_conditions.evalRecursive(((List) entry[1])); |
| } |
| } |
| else |
| { |
| m_stack.set(entry); |
| } |
| |
| return true; |
| } |
| |
| public void clearPD() |
| { |
| m_stack.set(null); |
| } |
| } |