You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2010/01/10 23:11:28 UTC

svn commit: r897721 [1/2] - in /felix/trunk/framework.security: ./ src/main/java/org/apache/felix/framework/ src/main/java/org/apache/felix/framework/security/ src/main/java/org/apache/felix/framework/security/condpermadmin/ src/main/java/org/apache/fe...

Author: pauls
Date: Sun Jan 10 22:11:27 2010
New Revision: 897721

URL: http://svn.apache.org/viewvc?rev=897721&view=rev
Log:
Add support for the 4.2.0 security specifications. This includes implementations of the access flag and various other changes (FELIX-1904, FELIX-22).

Removed:
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/verifier/SignerMatcher.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/verifier/SubjectDNParser.java
    felix/trunk/framework.security/src/main/java/org/osgi/service/condpermadmin/
Modified:
    felix/trunk/framework.security/pom.xml
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityActivator.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityProviderImpl.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/SecurityConstants.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionAdminImpl.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionInfoImpl.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/DomainGripper.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/permissionadmin/PermissionAdminImpl.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/BundleInputStream.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/Conditions.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/LocalPermissions.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/PropertiesCache.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/TrustManager.java
    felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/verifier/BundleDNParser.java

Modified: felix/trunk/framework.security/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/pom.xml?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/pom.xml (original)
+++ felix/trunk/framework.security/pom.xml Sun Jan 10 22:11:27 2010
@@ -34,7 +34,7 @@
      <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
-      <version>4.1.0</version>
+      <version>4.2.0</version>
     </dependency>
     <dependency>
       <groupId>${pom.groupId}</groupId>

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityActivator.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityActivator.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityActivator.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityActivator.java Sun Jan 10 22:11:27 2010
@@ -20,12 +20,9 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
 import java.util.StringTokenizer;
-import java.util.Map.Entry;
 
+import org.apache.felix.framework.ext.SecurityProvider;
 import org.apache.felix.framework.security.SecurityConstants;
 import org.apache.felix.framework.security.condpermadmin.ConditionalPermissionAdminImpl;
 import org.apache.felix.framework.security.permissionadmin.PermissionAdminImpl;
@@ -33,81 +30,72 @@
 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.security.verifier.BundleDNParser;
 import org.apache.felix.framework.util.SecureAction;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
 import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
 import org.osgi.service.permissionadmin.PermissionAdmin;
 
 /**
- * <p>This Felix specific activator installs a security provider with the Felix
+ * <p>
+ * This Felix specific activator installs a security provider with the Felix
  * framework. The security settings can be changed via the
- * {@link PermissionAdmin} and/or the
- * {@link ConditionalPermissionAdmin} services that may be published by
- * this class.
+ * {@link PermissionAdmin} and/or the {@link ConditionalPermissionAdmin}
+ * services that may be published by this class.
  * </p>
  * <p>
- * Permission informations as well as caching data will be stored in several 
- * files in a directory called <tt>security</tt> obtained by a call to 
+ * Permission informations as well as caching data will be stored in several
+ * files in a directory called <tt>security</tt> obtained by a call to
  * {@link BundleContext#getDataFile(String))}.
  * </p>
  * <p>
  * The following properties are recognized:
  * <p>
- * {@link SecurityConstants#ENABLE_PERMISSIONADMIN_PROP} - Whether or not 
- * (<tt>true</tt>|<tt>false</tt>) to
- * publish a{@link ConditionalPermissionAdmin} service. The default is
+ * {@link SecurityConstants#ENABLE_PERMISSIONADMIN_PROP} - Whether or not (
+ * <tt>true</tt>|<tt>false</tt>) to publish a{@link ConditionalPermissionAdmin}
+ * service. The default is
  * {@link SecurityConstants#ENABLE_PERMISSIONADMIN_VALUE}.
  * </p>
  * <p>
- * {@link SecurityConstants#ENABLE_CONDPERMADMIN_PROP} - Whether or not 
- * (<tt>true</tt>|<tt>false</tt>) to
- * publish a{@link ConditionalPermissionAdmin} service. The default is
- * {@link SecurityConstants#ENABLE_CONDPERMADMIN_VALUE}.
+ * {@link SecurityConstants#ENABLE_CONDPERMADMIN_PROP} - Whether or not (
+ * <tt>true</tt>|<tt>false</tt>) to publish a{@link ConditionalPermissionAdmin}
+ * service. The default is {@link SecurityConstants#ENABLE_CONDPERMADMIN_VALUE}.
  * </p>
  * <p>
  * {@link SecurityConstants#KEYSTORE_FILE_PROP} - The keystore URL(s) to use as
  * trusted CA stores. The urls must be separated by a guard (i.e., <tt>|</tt>).
- * The default is
- * {@link SecurityConstants#KEYSTORE_FILE_VALUE}.
+ * The default is {@link SecurityConstants#KEYSTORE_FILE_VALUE}.
  * </p>
  * <p>
  * {@link SecurityConstants#KEYSTORE_PASS_PROP} - The keystore password(s) to
- * use for the given keystores. The passwords must be separated by a guard 
+ * use for the given keystores. The passwords must be separated by a guard
  * (i.e., <tt>|</tt>).The default is
  * {@link SecurityConstants#KEYSTORE_PASS_VALUE}.
  * </p>
  * <p>
  * {@link SecurityConstants#KEYSTORE_TYPE_PROP} - The keystore type(s) to use
- * for the given keystores. The types must be separated by a guard 
- * (i.e., <tt>|</tt>).The default is
- * {@link SecurityConstants#KEYSTORE_TYPE_VALUE}.
+ * for the given keystores. The types must be separated by a guard (i.e.,
+ * <tt>|</tt>).The default is {@link SecurityConstants#KEYSTORE_TYPE_VALUE}.
  * </p>
  * <p>
  * {@link SecurityConstants#CRL_FILE_PROP} - The CRL URL(s) to use for revoked
- * certificates. The urls must be separated by a guard (i.e., <tt>|</tt>).
- * The default is {@link SecurityConstants#CRL_FILE_VALUE}.
+ * certificates. The urls must be separated by a guard (i.e., <tt>|</tt>). The
+ * default is {@link SecurityConstants#CRL_FILE_VALUE}.
  * </p>
  * </p>
  */
 /*
  * TODO: using a string for passwords is bad. We need to investigate
- * alternatives. 
+ * alternatives.
  * 
- * TODO: we might want to allow for the recognized properties to
- * change without a restart. This is trick because we can not publish a managed
- * service due to not being able to import as we are an extension bundle.
+ * TODO: we might want to allow for the recognized properties to change without
+ * a restart. This is trick because we can not publish a managed service due to
+ * not being able to import as we are an extension bundle.
  */
 public final class SecurityActivator implements BundleActivator
 {
-    private SecurityProviderImpl m_provider = null;
-    private PropertiesCache m_dnsCache = null;
-    private PropertiesCache m_localCache = null;
-    private LocalPermissions m_localPermissions = null;
-
     public synchronized void start(BundleContext context) throws Exception
     {
         PermissionAdminImpl pai = null;
@@ -135,15 +123,14 @@
             SecurityConstants.ENABLE_PERMISSIONADMIN_PROP,
             SecurityConstants.ENABLE_PERMISSIONADMIN_VALUE)))
         {
-            File cache =
-                context.getDataFile("security" + File.separator + "pa.txt");
+            File cache = context.getDataFile("security" + File.separator
+                + "pa.txt");
             if ((cache == null) || (!cache.isFile() && !cache.createNewFile()))
             {
                 throw new IOException("Can't create cache file");
             }
-            pai =
-                new PermissionAdminImpl(permissions, new PropertiesCache(cache,
-                    tmp, action));
+            pai = new PermissionAdminImpl(permissions, new PropertiesCache(
+                cache, tmp, action));
         }
 
         ConditionalPermissionAdminImpl cpai = null;
@@ -152,92 +139,72 @@
             SecurityConstants.ENABLE_CONDPERMADMIN_PROP,
             SecurityConstants.ENABLE_CONDPERMADMIN_VALUE)))
         {
-            File cpaCache =
-                context.getDataFile("security" + File.separator + "cpa.txt");
-            if ((cpaCache == null) || (!cpaCache.isFile() && !cpaCache.createNewFile()))
-            {
-                throw new IOException("Can't create cache file");
-            }
-            File localCache = 
-                context.getDataFile("security" + File.separator + "local.txt");
-            if ((localCache == null) || (!localCache.isFile() && !localCache.createNewFile()))
+            File cpaCache = context.getDataFile("security" + File.separator
+                + "cpa.txt");
+            if ((cpaCache == null)
+                || (!cpaCache.isFile() && !cpaCache.createNewFile()))
             {
                 throw new IOException("Can't create cache file");
             }
-            
-            m_localCache = new PropertiesCache(localCache, tmp, action);
-            m_localPermissions  = new LocalPermissions(permissions, m_localCache);
-            
-            cpai =
-                new ConditionalPermissionAdminImpl(permissions, new Conditions(
-                    action), m_localPermissions,
-                    new PropertiesCache(cpaCache, tmp, action));
+
+            LocalPermissions localPermissions = new LocalPermissions(
+                permissions);
+
+            cpai = new ConditionalPermissionAdminImpl(permissions,
+                new Conditions(action), localPermissions, new PropertiesCache(
+                    cpaCache, tmp, action), pai);
         }
 
         if ((pai != null) || (cpai != null))
         {
-            String crlList =
-                getProperty(context, SecurityConstants.CRL_FILE_PROP,
-                    SecurityConstants.CRL_FILE_VALUE);
-            String storeList =
-                getProperty(context, SecurityConstants.KEYSTORE_FILE_PROP,
-                    SecurityConstants.KEYSTORE_FILE_VALUE);
-            String passwdList =
-                getProperty(context, SecurityConstants.KEYSTORE_PASS_PROP,
-                    SecurityConstants.KEYSTORE_PASS_VALUE);
-            String typeList =
-                getProperty(context, SecurityConstants.KEYSTORE_TYPE_PROP,
-                    SecurityConstants.KEYSTORE_TYPE_VALUE);
+            String crlList = getProperty(context,
+                SecurityConstants.CRL_FILE_PROP,
+                SecurityConstants.CRL_FILE_VALUE);
+            String storeList = getProperty(context,
+                SecurityConstants.KEYSTORE_FILE_PROP,
+                SecurityConstants.KEYSTORE_FILE_VALUE);
+            String passwdList = getProperty(context,
+                SecurityConstants.KEYSTORE_PASS_PROP,
+                SecurityConstants.KEYSTORE_PASS_VALUE);
+            String typeList = getProperty(context,
+                SecurityConstants.KEYSTORE_TYPE_PROP,
+                SecurityConstants.KEYSTORE_TYPE_VALUE);
+            String osgi_keystores = getProperty(context,
+                Constants.FRAMEWORK_TRUST_REPOSITORIES, null);
+            if (osgi_keystores != null)
+            {
+                StringTokenizer tok = new StringTokenizer(osgi_keystores,
+                    File.pathSeparator);
+
+                if (storeList.length() == 0)
+                {
+                    storeList += "file:" + tok.nextToken();
+                    passwdList += " ";
+                    typeList += "JKS";
+                }
+                while (tok.hasMoreTokens())
+                {
+                    storeList += "|file:" + tok.nextToken();
+                    passwdList += "| ";
+                    typeList += "|JKS";
+                }
+            }
 
             StringTokenizer storeTok = new StringTokenizer(storeList, "|");
             StringTokenizer passwdTok = new StringTokenizer(passwdList, "|");
             StringTokenizer typeTok = new StringTokenizer(typeList, "|");
 
-            if ((storeTok.countTokens() != passwdTok.countTokens())
-                || (passwdTok.countTokens() != typeTok.countTokens()))
+            if ((storeTok.countTokens() != typeTok.countTokens())
+                || (passwdTok.countTokens() != storeTok.countTokens()))
             {
                 throw new BundleException(
                     "Each CACerts keystore must have one type and one passwd entry and vice versa.");
             }
 
-            m_provider =
-                new SecurityProviderImpl(crlList, typeList, passwdList,
-                    storeList, pai, cpai, action);
-
-            File cache =
-                context.getDataFile("security" + File.separator + "dns.txt");
-            if ((cache == null) || (!cache.isFile() && !cache.createNewFile()))
-            {
-                throw new IOException("Can't create cache file");
-            }
-            m_dnsCache = new PropertiesCache(cache, tmp, action);
-
-            Map store = m_dnsCache.read(String[].class);
-
-            if (store != null)
-            {
-                BundleDNParser parser = m_provider.getParser();
+            SecurityProvider provider = new SecurityProviderImpl(crlList,
+                typeList, passwdList, storeList, pai, cpai, action);
 
-                for (Iterator iter = store.entrySet().iterator(); iter
-                    .hasNext();)
-                {
-                    Entry entry = (Entry) iter.next();
-                    String[] value = (String[]) entry.getValue();
-                    if ("none".equals(value[0]))
-                    {
-                        parser.put((String) entry.getKey(), null);
-                    }
-                    else if ("invalid".equals(value[0]))
-                    {
-                        parser.put((String) entry.getKey(), new String[0]);
-                    }
-                    else
-                    {
-                        parser.put((String) entry.getKey(), value);
-                    }
-                }
-            }
-            ((Felix) context.getBundle(0)).setSecurityProvider(m_provider);
+            ((Felix) context.getBundle(0)).setSecurityProvider(provider);
         }
 
         if (pai != null)
@@ -254,59 +221,7 @@
 
     public synchronized void stop(BundleContext context) throws Exception
     {
-        if (m_provider != null)
-        {
-            m_dnsCache.write(write(m_provider.getParser().getCache(), context));
-        }
-        if (m_localPermissions != null)
-        {
-           m_localCache.write(write(m_localPermissions.getStore(), context));
-        }
-        m_provider = null;
-        m_dnsCache = null;
-        m_localPermissions = null;
-    }
-
-    private Map write(Map cache, BundleContext context)
-    {
-        // Filter the cached dn chains and only store the latest for each 
-        // bundle. This is ok because the framework will prune old revisions
-        // after a restart. The format is <id>-<timestamp>
-        Map store = new HashMap();
-        Map index = new HashMap();
-        for (Iterator iter = cache.entrySet().iterator(); iter.hasNext();)
-        {
-            Entry entry = (Entry) iter.next();
-            
-            String key = (String) entry.getKey();
-            String id = key.substring(0, key.indexOf("-"));
-            String time = key.substring(key.indexOf("-") + 1);
-            Bundle bundle = context.getBundle(Long.parseLong(id));
-            long timeLong = Long.parseLong(time);
-            if ((bundle == null) || 
-                (bundle.getLastModified() > timeLong))
-            {
-                continue;
-            }
-            String last = (String) index.get(id);
-
-            if ((last == null)
-                || (Long.parseLong(last) < timeLong))
-            {
-                index.put(id, time);
-                Object[] dns = (Object[]) entry.getValue();
-                store.remove(id + "-" + last);
-                if ((dns != null) && (dns.length > 0))
-                {
-                    store.put(key, dns);
-                }
-                else
-                {
-                    store.put(key, (dns == null) ? new String[] {"none"} : new String[] {"invalid"});
-                }
-            }
-        }
-        return store;
+        ((Felix) context.getBundle(0)).setSecurityProvider(null);
     }
 
     private String getProperty(BundleContext context, String key,
@@ -314,7 +229,6 @@
     {
         String result = context.getProperty(key);
 
-        return ((result != null) && (result.trim().length() > 0)) ? result
-            : defaultValue;
+        return (result != null) ? result : defaultValue;
     }
 }

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityProviderImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityProviderImpl.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityProviderImpl.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/SecurityProviderImpl.java Sun Jan 10 22:11:27 2010
@@ -26,13 +26,13 @@
 import org.apache.felix.framework.security.permissionadmin.PermissionAdminImpl;
 import org.apache.felix.framework.security.util.TrustManager;
 import org.apache.felix.framework.security.verifier.BundleDNParser;
-import org.apache.felix.framework.security.verifier.SignerMatcher;
 import org.apache.felix.framework.util.SecureAction;
+import org.apache.felix.moduleloader.IModule;
 import org.osgi.framework.Bundle;
 
 /**
- * This class is the entry point to the security. It is used to determine whether
- * a given bundle is signed correctely and has permissions based on 
+ * This class is the entry point to the security. It is used to determine
+ * whether a given bundle is signed correctely and has permissions based on
  * PermissionAdmin or ConditionalPermissionAdmin.
  */
 public final class SecurityProviderImpl implements SecurityProvider
@@ -42,69 +42,49 @@
     private final ConditionalPermissionAdminImpl m_cpai;
     private final SecureAction m_action;
 
-    SecurityProviderImpl(String crlList, String typeList,
-        String passwdList, String storeList, PermissionAdminImpl pai,
+    SecurityProviderImpl(String crlList, String typeList, String passwdList,
+        String storeList, PermissionAdminImpl pai,
         ConditionalPermissionAdminImpl cpai, SecureAction action)
     {
         m_pai = pai;
         m_cpai = cpai;
         m_action = action;
-        m_parser =
-            new BundleDNParser(new TrustManager(crlList, typeList, passwdList,
-                storeList, m_action));
-    }
-
-    BundleDNParser getParser()
-    {
-        return m_parser;
+        m_parser = new BundleDNParser(new TrustManager(crlList, typeList,
+            passwdList, storeList, m_action));
     }
 
     /**
-     * If the given bundle is signed but can not be verified (e.g., missing files)
-     * then throw an exception.
+     * If the given bundle is signed but can not be verified (e.g., missing
+     * files) then throw an exception.
      */
     public void checkBundle(Bundle bundle) throws Exception
     {
-        m_parser.checkDNChains(
-            (Long.toString(bundle.getBundleId()) + "-" + bundle.getLastModified()), 
-            ((BundleImpl) bundle).getCurrentModule().getContent());
+        IModule module = ((BundleImpl) bundle).getCurrentModule();
+        m_parser.checkDNChains(module, module.getContent(),
+            Bundle.SIGNERS_TRUSTED);
     }
 
     /**
      * Get a signer matcher that can be used to match digital signed bundles.
      */
-    public Object getSignerMatcher(final Bundle bundle)
+    public Object getSignerMatcher(final Bundle bundle, int signersType)
     {
-        return new SignerMatcher(Long.toString(bundle.getBundleId()), 
-            bundle.getLastModified(),
-            ((BundleImpl) bundle).getCurrentModule().getContent(), 
-            m_parser);
+        IModule module = ((BundleImpl) bundle).getCurrentModule();
+        return m_parser.getDNChains(module, module.getContent(), signersType);
     }
 
-    ThreadLocal loopCheck = new ThreadLocal();
-    
     /**
-     * If we have a permissionadmin then ask that one first and have it
-     * decide in case there is a location bound. If not then either use its 
-     * default permission in case there is no conditional permission admin
-     * or else ask that one. 
+     * If we have a permissionadmin then ask that one first and have it decide
+     * in case there is a location bound. If not then either use its default
+     * permission in case there is no conditional permission admin or else ask
+     * that one.
      */
     public boolean hasBundlePermission(ProtectionDomain bundleProtectionDomain,
         Permission permission, boolean direct)
     {
-    	if (loopCheck.get() != null)
-    	{
-    		return true;
-    	}
-    	else
-    	{
-    	    loopCheck.set(this);
-    	}
-    	try
-    	{
-        BundleProtectionDomain pd =
-            (BundleProtectionDomain) bundleProtectionDomain;
+        BundleProtectionDomain pd = (BundleProtectionDomain) bundleProtectionDomain;
         BundleImpl bundle = pd.getBundle();
+        IModule module = pd.getModule();
 
         if (bundle.getBundleId() == 0)
         {
@@ -116,13 +96,22 @@
         Boolean result = null;
         if (m_pai != null)
         {
-            result =
-                m_pai.hasPermission(bundle.getLocation(), pd.getBundle(),
-                    permission, m_cpai, pd);
+            result = m_pai.hasPermission(bundle._getLocation(), pd.getBundle(),
+                permission, m_cpai, pd, bundle.getCurrentModule().getContent());
         }
 
         if (result != null)
         {
+            if ((m_cpai != null) && !direct)
+            {
+                boolean allow = result.booleanValue();
+                if (!allow)
+                {
+                    m_cpai.clearPD();
+                    return false;
+                }
+                return m_cpai.handlePAHandle(pd);
+            }
             return result.booleanValue();
         }
 
@@ -130,10 +119,7 @@
         {
             try
             {
-                return m_cpai.hasPermission(bundle, 
-                    bundle.getCurrentModule().getContent(), 
-                    bundle.getBundleId() + "-" + 
-                    bundle.getLastModified(),null, pd,
+                return m_cpai.hasPermission(module, module.getContent(), pd,
                     permission, direct, m_pai);
             }
             catch (Exception e)
@@ -144,8 +130,5 @@
         }
 
         return false;
-    	} finally {
-    		loopCheck.set(null);
-    	}
     }
 }
\ No newline at end of file

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/SecurityConstants.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/SecurityConstants.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/SecurityConstants.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/SecurityConstants.java Sun Jan 10 22:11:27 2010
@@ -18,38 +18,29 @@
  */
 package org.apache.felix.framework.security;
 
-import java.io.File;
-
 public interface SecurityConstants
 {
     public static final String KEYSTORE_FILE_PROP = "felix.keystore";
 
-    public static final String KEYSTORE_FILE_VALUE = "file:" +
-        System.getProperty("java.home") + File.separatorChar + "lib"
-            + File.separatorChar + "security" + File.separatorChar + "cacerts"
-            + "|file:" + System.getProperty("user.home") + File.separatorChar
-            + ".keystore";
+    public static final String KEYSTORE_FILE_VALUE = "";
 
     public static final String KEYSTORE_TYPE_PROP = "felix.keystore.type";
 
-    public static final String KEYSTORE_TYPE_VALUE = "JKS" + "|" + "JKS";
+    public static final String KEYSTORE_TYPE_VALUE = "";
 
     public static final String KEYSTORE_PASS_PROP = "felix.keystore.pass";
 
-    public static final String KEYSTORE_PASS_VALUE =
-        "changeit" + "|" + "changeit";
+    public static final String KEYSTORE_PASS_VALUE = "";
 
     public static final String CRL_FILE_PROP = "felix.crl";
 
     public static final String CRL_FILE_VALUE = "";
 
-    public static final String ENABLE_CONDPERMADMIN_PROP =
-        "felix.security.conpermadmin";
+    public static final String ENABLE_CONDPERMADMIN_PROP = "felix.security.conpermadmin";
 
     public static final String ENABLE_CONDPERMADMIN_VALUE = "true";
 
-    public static final String ENABLE_PERMISSIONADMIN_PROP =
-        "felix.security.permissionadmin";
+    public static final String ENABLE_PERMISSIONADMIN_PROP = "felix.security.permissionadmin";
 
     public static final String ENABLE_PERMISSIONADMIN_VALUE = "true";
 }

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionAdminImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionAdminImpl.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionAdminImpl.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionAdminImpl.java Sun Jan 10 22:11:27 2010
@@ -19,70 +19,222 @@
 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.AccessController;
-import java.security.DomainCombiner;
+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.IteratorToEnumeration;
+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.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.  
+ * 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 HashMap();
+    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) throws IOException
+        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.
-        Map old = m_propertiesCache.read(ConditionalPermissionInfoImpl.class);
-        if (old != null)
+        m_propertiesCache.read(ConditionalPermissionInfoImpl.class, old);
+        for (Iterator iter = old.entrySet().iterator(); iter.hasNext();)
         {
-            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));
-            }
+            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(
@@ -93,9 +245,8 @@
         {
             ((SecurityManager) sm).checkPermission(Permissions.ALL_PERMISSION);
         }
-        ConditionalPermissionInfoImpl result =
-            new ConditionalPermissionInfoImpl(notNull(conditions),
-                notNull(permissions), this);
+        ConditionalPermissionInfoImpl result = new ConditionalPermissionInfoImpl(
+            notNull(conditions), notNull(permissions), this, true);
 
         return write(result.getName(), result);
     }
@@ -109,7 +260,8 @@
 
             synchronized (m_condPermInfos)
             {
-                tmp = new HashMap(m_condPermInfos);
+                tmp = new OrderedHashMap();
+                tmp.putAll(m_condPermInfos);
 
                 if ((name != null) && (cpi != null))
                 {
@@ -133,8 +285,11 @@
             {
                 synchronized (m_condPermInfos)
                 {
-                    m_condPermInfos.clear();
-                    m_condPermInfos.putAll(tmp);
+                    if (tmp != null)
+                    {
+                        m_condPermInfos.clear();
+                        m_condPermInfos.putAll(tmp);
+                    }
                 }
                 ex.printStackTrace();
                 throw new IllegalStateException(ex.getMessage());
@@ -146,28 +301,485 @@
         }
     }
 
-    // TODO: this is pretty much untested so it might not work like this
-    public AccessControlContext getAccessControlContext(String[] signers)
+    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)
     {
-        final String[] finalSigners =
-            (String[]) notNull(signers).toArray(new String[0]);
-        return new AccessControlContext(AccessController.getContext(),
-            new DomainCombiner()
+        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++)
             {
-                public ProtectionDomain[] combine(ProtectionDomain[] arg0,
-                    ProtectionDomain[] arg1)
+                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 IModule()
                 {
-                    return new ProtectionDomain[] { new ProtectionDomain(null,
-                        null)
+
+                    public Bundle getBundle()
                     {
-                        public boolean implies(Permission permission)
-                        {
-                            return hasPermission(null, null, null, finalSigners,
-                                this, permission, true, null);
-                        }
-                    } };
+                        return fake;
+                    }
+
+                    public ICapability[] getCapabilities()
+                    {
+                        return null;
+                    }
+
+                    public Class getClassByDelegation(String arg0)
+                        throws ClassNotFoundException
+                    {
+                        return null;
+                    }
+
+                    public IContent getContent()
+                    {
+                        return null;
+                    }
+
+                    public int getDeclaredActivationPolicy()
+                    {
+                        return 0;
+                    }
+
+                    public IRequirement[] 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 R4Library[] getNativeLibraries()
+                    {
+                        return null;
+                    }
+
+                    public IRequirement[] 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 IWire[] 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)
+                    {
+                    }
+                }, 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)
@@ -185,7 +797,7 @@
 
         if (result == null)
         {
-            result = new ConditionalPermissionInfoImpl(this, name);
+            result = new ConditionalPermissionInfoImpl(this, name, true);
 
             result = write(result.getName(), result);
         }
@@ -219,14 +831,13 @@
         {
             synchronized (m_condPermInfos)
             {
-                result =
-                    (ConditionalPermissionInfoImpl) m_condPermInfos.get(name);
+                result = (ConditionalPermissionInfoImpl) m_condPermInfos
+                    .get(name);
 
                 if (result == null)
                 {
-                    result =
-                        new ConditionalPermissionInfoImpl(name, conditions,
-                            permissions, this);
+                    result = new ConditionalPermissionInfoImpl(name,
+                        conditions, permissions, this, true);
                 }
                 else
                 {
@@ -236,8 +847,8 @@
         }
         else
         {
-            result =
-                new ConditionalPermissionInfoImpl(conditions, permissions, this);
+            result = new ConditionalPermissionInfoImpl(conditions, permissions,
+                this, true);
         }
 
         return write(result.getName(), result);
@@ -284,87 +895,84 @@
 
     /**
      * 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.
+     * 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.
+     * @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(Bundle felixBundle, IContent content, String root, 
-        String[] signers, ProtectionDomain pd, Permission permission,
-        boolean direct, Object admin)
+    public boolean hasPermission(IModule module, IContent 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 
+        // first see whether this is the normal case (the special case is for
         // the ACC based on signers).
-        if (signers == null)
+        // In case of a direct call we don't need to look for other pds
+        if (direct)
         {
-            // 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)
             {
-                domains = new ArrayList();
-                tuples = new ArrayList();
-                domains.add(pd);
+                entry = new Object[] { new ArrayList(DomainGripper.grab()),
+                    new ArrayList() };
             }
             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);
-                }
+                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);
-                }
+            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 (!m_localPermissions.implies(root, content, felixBundle, permission))
+        if (!impliesLocal(module.getBundle(), content, permission))
         {
             return false;
         }
 
         List posts = new ArrayList();
 
-        boolean result = eval(posts, felixBundle, signers, permission, admin);
-
-        if (signers != null)
-        {
-            return result;
-        }
+        boolean result = eval(posts, module, permission, admin);
 
         domains.remove(pd);
 
@@ -378,7 +986,8 @@
         if (domains.isEmpty())
         {
             m_stack.set(null);
-            // Now eval the postponed tupels. if the previous eval did return false
+            // 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())
             {
@@ -387,7 +996,8 @@
         }
         else
         {
-            // this is to support recursive permission checks. In case we trigger
+            // 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);
         }
@@ -395,6 +1005,12 @@
         return result;
     }
 
+    public boolean impliesLocal(Bundle felixBundle, IContent content,
+        Permission permission)
+    {
+        return m_localPermissions.implies(content, felixBundle, permission);
+    }
+
     public boolean isEmpty()
     {
         synchronized (m_condPermInfos)
@@ -408,8 +1024,8 @@
     // 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, Bundle bundle, String[] signers,
-        Permission permission, Object admin)
+    private boolean eval(List posts, IModule module, Permission permission,
+        Object admin)
     {
         List condPermInfos = null;
 
@@ -423,25 +1039,26 @@
         }
 
         // Check for implicit permissions like access to file area
-        if ((bundle != null)
-            && m_permissions.getPermissions(m_permissions.getImplicit(bundle))
-                .implies(permission, bundle))
+        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();
+            ConditionalPermissionInfoImpl cpi = (ConditionalPermissionInfoImpl) iter
+                .next();
 
             ConditionInfo[] conditions = cpi._getConditionInfos();
 
             List currentPosts = new ArrayList();
 
-            if (!m_conditions.getConditions(bundle, signers, conditions)
-                .isSatisfied(currentPosts))
+            Conditions conds = m_conditions.getConditions(module, conditions);
+            if (!conds.isSatisfied(currentPosts, m_permissions
+                .getPermissions(cpi._getPermissionInfos()), permission))
             {
                 continue;
             }
@@ -454,13 +1071,127 @@
 
             if (currentPosts.isEmpty())
             {
-                posts.clear();
+                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;
             }
 
-            posts.add(currentPosts);
+            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() };
         }
 
-        return !posts.isEmpty();
+        ((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);
     }
 }

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionInfoImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionInfoImpl.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionInfoImpl.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/ConditionalPermissionInfoImpl.java Sun Jan 10 22:11:27 2010
@@ -30,15 +30,17 @@
 
 /**
  * Simple storage class for condperminfos. Additionally, this class can be used
- * to encode and decode infos. 
+ * to encode and decode infos.
  */
-public final class ConditionalPermissionInfoImpl implements ConditionalPermissionInfo
+public final class ConditionalPermissionInfoImpl implements
+    ConditionalPermissionInfo
 {
     private static final Random RANDOM = new Random();
     static final ConditionInfo[] CONDITION_INFO = new ConditionInfo[0];
     static final PermissionInfo[] PERMISSION_INFO = new PermissionInfo[0];
     private final Object m_lock = new Object();
     private final String m_name;
+    private final boolean m_allow;
     private volatile ConditionalPermissionAdminImpl m_cpai;
     private ConditionInfo[] m_conditions;
     private PermissionInfo[] m_permissions;
@@ -46,16 +48,18 @@
     public ConditionalPermissionInfoImpl(String encoded)
     {
         StringTokenizer tok = new StringTokenizer(encoded, "\n");
-        if (!tok.nextToken().trim().equals("{"))
+        String access = tok.nextToken().trim();
+        if (!(access.equals("ALLOW {") || access.equals("DENY {")))
         {
             throw new IllegalArgumentException();
         }
+        m_allow = access.equals("ALLOW {");
         m_cpai = null;
         m_name = tok.nextToken().trim().substring(1);
         List conditions = new ArrayList();
         List permissions = new ArrayList();
-        for (String current = tok.nextToken().trim();; current =
-            tok.nextToken().trim())
+        for (String current = tok.nextToken().trim();; current = tok
+            .nextToken().trim())
         {
             if (current.equals("}"))
             {
@@ -78,19 +82,18 @@
             }
         }
 
-        m_conditions =
-            conditions.isEmpty() ? CONDITION_INFO
-                : (ConditionInfo[]) conditions
-                    .toArray(new ConditionInfo[conditions.size()]);
-        m_permissions =
-            permissions.isEmpty() ? PERMISSION_INFO
-                : (PermissionInfo[]) permissions
-                    .toArray(new PermissionInfo[permissions.size()]);
+        m_conditions = conditions.isEmpty() ? CONDITION_INFO
+            : (ConditionInfo[]) conditions.toArray(new ConditionInfo[conditions
+                .size()]);
+        m_permissions = permissions.isEmpty() ? PERMISSION_INFO
+            : (PermissionInfo[]) permissions
+                .toArray(new PermissionInfo[permissions.size()]);
     }
 
     public ConditionalPermissionInfoImpl(ConditionalPermissionAdminImpl cpai,
-        String name)
+        String name, boolean access)
     {
+        m_allow = access;
         m_name = name;
         m_cpai = cpai;
         m_conditions = CONDITION_INFO;
@@ -98,8 +101,10 @@
     }
 
     public ConditionalPermissionInfoImpl(ConditionInfo[] conditions,
-        PermissionInfo[] permisions, ConditionalPermissionAdminImpl cpai)
+        PermissionInfo[] permisions, ConditionalPermissionAdminImpl cpai,
+        boolean access)
     {
+        m_allow = access;
         m_name = Long.toString(RANDOM.nextLong() ^ System.currentTimeMillis());
         m_cpai = cpai;
         m_conditions = conditions;
@@ -108,9 +113,11 @@
 
     public ConditionalPermissionInfoImpl(String name,
         ConditionInfo[] conditions, PermissionInfo[] permisions,
-        ConditionalPermissionAdminImpl cpai)
+        ConditionalPermissionAdminImpl cpai, boolean access)
     {
-        m_name = name;
+        m_allow = access;
+        m_name = (name != null) ? name : Long.toString(RANDOM.nextLong()
+            ^ System.currentTimeMillis());
         m_conditions = conditions;
         m_permissions = permisions;
         m_cpai = cpai;
@@ -182,6 +189,7 @@
     public String getEncoded()
     {
         StringBuffer buffer = new StringBuffer();
+        buffer.append(m_allow ? "ALLOW " : "DENY ");
         buffer.append('{');
         buffer.append('\n');
         buffer.append('#');
@@ -209,4 +217,15 @@
     {
         return getEncoded();
     }
+
+    public String getAccessDecision()
+    {
+        return m_allow ? ConditionalPermissionInfo.ALLOW
+            : ConditionalPermissionInfo.DENY;
+    }
+
+    public boolean isAllow()
+    {
+        return m_allow;
+    }
 }

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/DomainGripper.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/DomainGripper.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/DomainGripper.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/condpermadmin/DomainGripper.java Sun Jan 10 22:11:27 2010
@@ -31,19 +31,19 @@
 import org.apache.felix.framework.BundleProtectionDomain;
 
 /**
- * This class is a hack to get all BundleProtectionDomains currently on the 
+ * This class is a hack to get all BundleProtectionDomains currently on the
  * security stack. This way we don't need to have our own security manager set.
  */
 final class DomainGripper implements DomainCombiner, PrivilegedAction
 {
-    private static final ProtectionDomain[] ALL_PERMISSION_PD =
-        new ProtectionDomain[] { new ProtectionDomain(null, null)
+    private static final ProtectionDomain[] ALL_PERMISSION_PD = new ProtectionDomain[] { new ProtectionDomain(
+        null, null)
+    {
+        public boolean implies(Permission perm)
         {
-            public boolean implies(Permission perm)
-            {
-                return true;
-            }
-        } };
+            return true;
+        }
+    } };
 
     // A per thread cache of DomainGripper objects. We might want to wrap them
     // in a softreference eventually
@@ -56,8 +56,8 @@
     private AccessControlContext m_system = null;
 
     /**
-     * Get all bundle protection domains and add them to the m_domains. Then 
-     * return the ALL_PERMISSION_PD. 
+     * Get all bundle protection domains and add them to the m_domains. Then
+     * return the ALL_PERMISSION_PD.
      */
     public ProtectionDomain[] combine(ProtectionDomain[] current,
         ProtectionDomain[] assigned)
@@ -84,7 +84,7 @@
     }
 
     /**
-     * Get the current bundle protection domains on the stack up to the last 
+     * Get the current bundle protection domains on the stack up to the last
      * privileged call.
      */
     public static List grab()
@@ -107,8 +107,8 @@
         gripper.m_system = AccessController.getContext();
 
         // and merge it with the current combiner (i.e., gripper)
-        AccessControlContext context =
-            (AccessControlContext) AccessController.doPrivileged(gripper);
+        AccessControlContext context = (AccessControlContext) AccessController
+            .doPrivileged(gripper);
 
         gripper.m_system = null;
 

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/permissionadmin/PermissionAdminImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/permissionadmin/PermissionAdminImpl.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/permissionadmin/PermissionAdminImpl.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/permissionadmin/PermissionAdminImpl.java Sun Jan 10 22:11:27 2010
@@ -30,22 +30,23 @@
 import org.apache.felix.framework.security.condpermadmin.ConditionalPermissionAdminImpl;
 import org.apache.felix.framework.security.util.Permissions;
 import org.apache.felix.framework.security.util.PropertiesCache;
+import org.apache.felix.moduleloader.IContent;
 import org.osgi.framework.Bundle;
 import org.osgi.service.permissionadmin.PermissionAdmin;
 import org.osgi.service.permissionadmin.PermissionInfo;
 
 /**
- * This class is a relatively straight forward implementation of the PermissionAdmin service.
- * The only somewhat involved thing is that it respects the presents of a
- * conditionalpermissionadmin service as per spec.
+ * This class is a relatively straight forward implementation of the
+ * PermissionAdmin service. The only somewhat involved thing is that it respects
+ * the presents of a conditionalpermissionadmin service as per spec.
  */
-// TODO: Do we need this class at all or can we just emulate it using the condpermadmin?
+// TODO: Do we need this class at all or can we just emulate it using the
+// condpermadmin?
 public final class PermissionAdminImpl implements PermissionAdmin
 {
-    private static final PermissionInfo[] ALL_PERMISSION =
-        new PermissionInfo[] { new PermissionInfo(
-            AllPermission.class.getName(), "", "") };
-    
+    private static final PermissionInfo[] ALL_PERMISSION = new PermissionInfo[] { new PermissionInfo(
+        AllPermission.class.getName(), "", "") };
+
     private final Map m_store = new HashMap();
 
     private final PropertiesCache m_cache;
@@ -59,11 +60,7 @@
     {
         m_permissions = permissions;
         m_cache = cache;
-        Map old = m_cache.read(PermissionInfo[].class);
-        if (old != null)
-        {
-            m_store.putAll(old);
-        }
+        m_cache.read(PermissionInfo[].class, m_store);
     }
 
     public PermissionInfo[] getDefaultPermissions()
@@ -106,71 +103,76 @@
     }
 
     /**
-     * This will do the actual permission check as described in the core spec 10.2
-     * It will respect a present condpermadmin service as described in 9.10.
+     * This will do the actual permission check as described in the core spec
+     * 10.2 It will respect a present condpermadmin service as described in
+     * 9.10.
      * 
-     * @param location the location of the bundle.
-     * @param bundle the bundle in question.
-     * @param permission the permission to check.
-     * @param cpai A condpermadmin if one is present else null.
-     * @param pd the protectiondomain
-     * @return Boolean.TRUE if the location is bound and the permission is 
-     *  granted or if there is no cpa and the default permissions imply the 
-     *  permission Boolean.FALSE otherwise unless the location is not bound and 
-     *  their is a cpa in which case null is returned.
+     * @param location
+     *            the location of the bundle.
+     * @param bundle
+     *            the bundle in question.
+     * @param permission
+     *            the permission to check.
+     * @param cpai
+     *            A condpermadmin if one is present else null.
+     * @param pd
+     *            the protectiondomain
+     * @return Boolean.TRUE if the location is bound and the permission is
+     *         granted or if there is no cpa and the default permissions imply
+     *         the permission Boolean.FALSE otherwise unless the location is not
+     *         bound and their is a cpa in which case null is returned.
      */
     public Boolean hasPermission(String location, Bundle bundle,
         Permission permission, ConditionalPermissionAdminImpl cpai,
-        ProtectionDomain pd)
+        ProtectionDomain pd, IContent content)
     {
         PermissionInfo[] permissions = null;
-        boolean file = false;
+        PermissionInfo[] defaults = null;
+        boolean contains = false;
         synchronized (m_store)
         {
-            if (m_store.containsKey(location))
+            contains = m_store.containsKey(location);
+            permissions = (PermissionInfo[]) m_store.get(location);
+            defaults = m_default;
+        }
+        if (contains)
+        {
+            if (check(permissions, permission, bundle))
             {
-                permissions = (PermissionInfo[]) m_store.get(location);
-                file = true;
+                return Boolean.TRUE;
             }
-            else if ((cpai == null) || (cpai.isEmpty()))
+            return check(m_permissions.getImplicit(bundle), permission, bundle) ? Boolean.TRUE
+                : Boolean.FALSE;
+        }
+        else if (cpai == null
+            || (cpai.isEmpty() && cpai
+                .impliesLocal(bundle, content, permission)))
+        {
+            if (defaults != null)
             {
-                if (m_default != null)
+                if (check(defaults, permission, null))
                 {
-                    permissions = m_default;
-                }
-                else
-                {
-                    permissions = ALL_PERMISSION;
+                    return Boolean.TRUE;
                 }
+                return check(m_permissions.getImplicit(bundle), permission,
+                    bundle) ? Boolean.TRUE : Boolean.FALSE;
             }
-        }
-        if ((cpai == null) || cpai.isEmpty() || file)
-        {
-            if (check(permissions, permission, file ? bundle : null))
+            else
             {
                 return Boolean.TRUE;
             }
         }
-
-        permissions = m_permissions.getImplicit(bundle);
-
-        if (check(permissions, permission, bundle))
-        {
-            return Boolean.TRUE;
-        }
-
-        if ((cpai != null) && !file)
+        else
         {
             return null;
         }
-        return Boolean.FALSE;
     }
 
     private boolean check(PermissionInfo[] permissions, Permission permission,
         Bundle bundle)
     {
-        Permissions permissionsObject =
-            m_permissions.getPermissions(permissions);
+        Permissions permissionsObject = m_permissions
+            .getPermissions(permissions);
 
         return permissionsObject.implies(permission, bundle);
     }

Modified: felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/BundleInputStream.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/BundleInputStream.java?rev=897721&r1=897720&r2=897721&view=diff
==============================================================================
--- felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/BundleInputStream.java (original)
+++ felix/trunk/framework.security/src/main/java/org/apache/felix/framework/security/util/BundleInputStream.java Sun Jan 10 22:11:27 2010
@@ -33,27 +33,27 @@
 import org.apache.felix.moduleloader.IContent;
 
 /**
- * This class makes a given content available as a inputstream with a jar content.
- * In other words the stream can be used as input to a JarInputStream. 
+ * This class makes a given content available as a inputstream with a jar
+ * content. In other words the stream can be used as input to a JarInputStream.
  */
 public final class BundleInputStream extends InputStream
 {
     private final IContent m_root;
     private final Enumeration m_content;
     private final OutputStreamBuffer m_outputBuffer = new OutputStreamBuffer();
-    
+
     private ByteArrayInputStream m_buffer = null;
     private JarOutputStream m_output = null;
-    
-    public BundleInputStream(IContent root) throws IOException 
+
+    public BundleInputStream(IContent root) throws IOException
     {
         m_root = root;
-        
+
         List entries = new ArrayList();
-        
+
         int count = 0;
         String manifest = null;
-        for (Enumeration e = m_root.getEntries();e.hasMoreElements();)
+        for (Enumeration e = m_root.getEntries(); e.hasMoreElements();)
         {
             String entry = (String) e.nextElement();
             if (entry.equalsIgnoreCase("META-INF/MANIFEST.MF"))
@@ -77,16 +77,16 @@
             manifest = "META-INF/MANIFEST.MF";
         }
         m_content = new IteratorToEnumeration(entries.iterator());
-        
+
         try
         {
             m_output = new JarOutputStream(m_outputBuffer);
             readNext(manifest);
-            m_buffer = new ByteArrayInputStream(
-                m_outputBuffer.m_outBuffer.toByteArray());
+            m_buffer = new ByteArrayInputStream(m_outputBuffer.m_outBuffer
+                .toByteArray());
 
             m_outputBuffer.m_outBuffer = null;
-        } 
+        }
         catch (IOException ex)
         {
             // TODO: figure out what is wrong
@@ -111,24 +111,24 @@
                 m_buffer = null;
                 return read();
             }
-            
+
             return result;
         }
 
         if (m_content.hasMoreElements())
         {
             String current = (String) m_content.nextElement();
-            
+
             readNext(current);
-            
+
             if (!m_content.hasMoreElements())
             {
                 m_output.close();
                 m_output = null;
             }
 
-            m_buffer = new ByteArrayInputStream(
-                m_outputBuffer.m_outBuffer.toByteArray());
+            m_buffer = new ByteArrayInputStream(m_outputBuffer.m_outBuffer
+                .toByteArray());
 
             m_outputBuffer.m_outBuffer = null;
         }
@@ -149,7 +149,7 @@
             {
                 throw new IOException("Missing entry");
             }
-            
+
             JarEntry entry = new JarEntry(path);
 
             m_output.putNextEntry(entry);
@@ -169,7 +169,7 @@
                 {
                     in.close();
                 }
-                catch (Exception ex) 
+                catch (Exception ex)
                 {
                     // Not much we can do
                 }
@@ -180,7 +180,7 @@
 
         m_output.flush();
     }
-    
+
     private static final class OutputStreamBuffer extends OutputStream
     {
         ByteArrayOutputStream m_outBuffer = null;
@@ -189,12 +189,12 @@
         {
             m_outBuffer.write(b);
         }
-        
+
         public void write(byte[] buffer) throws IOException
         {
             m_outBuffer.write(buffer);
-        }       
-        
+        }
+
         public void write(byte[] buffer, int offset, int length)
         {
             m_outBuffer.write(buffer, offset, length);