Package org.apache.felix.framework.security.util

Source Code of org.apache.felix.framework.security.util.Permissions$Entry

/*
* 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.util;

import java.io.File;
import java.io.FilePermission;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.AllPermission;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

import org.apache.felix.framework.util.SecureAction;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.service.permissionadmin.PermissionInfo;

/**
* A permission cache that uses permisssion infos as keys. Permission are
* created from the parent classloader or any exported package.
*/
// TODO: maybe use bundle events instead of soft/weak references
public final class Permissions
{
    private static final ClassLoader m_classLoader = Permissions.class
        .getClassLoader();

    private static final Map m_permissionCache = new HashMap();
    private static final Map m_permissions = new HashMap();
    private static final ReferenceQueue m_permissionsQueue = new ReferenceQueue();

    private static final ThreadLocal m_stack = new ThreadLocal();

    private final Map m_cache;
    private final ReferenceQueue m_queue;
    private final BundleContext m_context;
    private final PermissionInfo[] m_permissionInfos;
    private final boolean m_allPermission;
    private final SecureAction m_action;

    public static final AllPermission ALL_PERMISSION = new AllPermission();

    private static final PermissionInfo[] IMPLICIT = new PermissionInfo[] { new PermissionInfo(
        FilePermission.class.getName(), "-", "read,write,delete") };

    Permissions(PermissionInfo[] permissionInfos, BundleContext context,
        SecureAction action)
    {
        m_context = context;
        m_permissionInfos = permissionInfos;
        m_cache = new HashMap();
        m_queue = new ReferenceQueue();
        m_action = action;
        for (int i = 0; i < m_permissionInfos.length; i++)
        {
            if (m_permissionInfos[i].getType().equals(
                AllPermission.class.getName()))
            {
                m_allPermission = true;
                return;
            }
        }
        m_allPermission = false;
    }

    public Permissions(BundleContext context, SecureAction action)
    {
        m_context = context;
        m_permissionInfos = null;
        m_cache = null;
        m_queue = null;
        m_allPermission = true;
        m_action = action;
    }

    public PermissionInfo[] getImplicit(Bundle bundle)
    {
        return new PermissionInfo[] {
            IMPLICIT[0],
            new PermissionInfo(AdminPermission.class.getName(), "(id="
                + bundle.getBundleId() + ")", AdminPermission.METADATA),
            new PermissionInfo(AdminPermission.class.getName(), "(id="
                + bundle.getBundleId() + ")", AdminPermission.RESOURCE),
            new PermissionInfo(AdminPermission.class.getName(), "(id="
                + bundle.getBundleId() + ")", AdminPermission.CONTEXT) };
    }

    public Permissions getPermissions(PermissionInfo[] permissionInfos)
    {
        cleanUp(m_permissionsQueue, m_permissions);

        Permissions result = null;
        synchronized (m_permissions)
        {
            result = (Permissions) m_permissions.get(new Entry(permissionInfos));
        }
        if (result == null)
        {
      //permissionInfos may not be referenced by the new Permissions, as
      //otherwise the reference in m_permissions prevents the key from
      //being garbage collectable.
            PermissionInfo[] permissionInfosClone = new PermissionInfo[permissionInfos.length];
            System.arraycopy(permissionInfos, 0, permissionInfosClone, 0, permissionInfos.length);
            result = new Permissions(permissionInfosClone, m_context, m_action);
            synchronized (m_permissions)
            {
                m_permissions.put(
                    new Entry(permissionInfos, m_permissionsQueue), result);
            }
        }
        return result;
    }

    private static final class Entry extends WeakReference
    {
        private final int m_hashCode;

        Entry(Object entry, ReferenceQueue queue)
        {
            super(entry, queue);
            m_hashCode = entry.hashCode();
        }

        Entry(Object entry)
        {
            super(entry);
            m_hashCode = entry.hashCode();
        }

        public Object get()
        {
            return super.get();
        }

        public int hashCode()
        {
            return m_hashCode;
        }

        public boolean equals(Object o)
        {
            if (o == null)
            {
                return false;
            }

            if (o == this)
            {
                return true;
            }

            Object entry = super.get();

            if (o instanceof Entry)
            {

                Object otherEntry = ((Entry) o).get();
        if (entry == null)
        {
          return otherEntry == null;
        }
        if (otherEntry == null)
        {
          return false;
        }
        if (!entry.getClass().equals(otherEntry.getClass()))
        {
          return false;
        }
        if (entry instanceof Object[])
        {
          return Arrays.equals((Object[])entry, (Object[])otherEntry);
        }   
                return entry.equals(((Entry) o).get());
            }
            else
            {
                return false;
            }
        }
    }

    private static final class DefaultPermissionCollection extends
        PermissionCollection
    {
        private final Map m_perms = new HashMap();

        public void add(Permission perm)
        {
            synchronized (m_perms)
            {
                m_perms.put(perm, perm);
            }
        }

        public Enumeration elements()
        {
            throw new IllegalStateException("Not implemented");
        }

        public boolean implies(Permission perm)
        {
            Map perms = null;

            synchronized (m_perms)
            {
                perms = m_perms;
            }

            Permission permission = (Permission) perms.get(perm);

            if ((permission != null) && permission.implies(perm))
            {
                return true;
            }

            for (Iterator iter = perms.values().iterator(); iter.hasNext();)
            {
                Permission current = (Permission) iter.next();
                if ((current != null) && (current != permission)
                    && current.implies(perm))
                {
                    return true;
                }
            }
            return false;
        }
    }

    private void cleanUp(ReferenceQueue queue, Map cache)
    {
        for (Entry entry = (Entry) queue.poll(); entry != null; entry = (Entry) queue
            .poll())
        {
            synchronized (cache)
            {
                cache.remove(entry);
            }
        }
    }

    /**
     * @param target
     *            the permission to be implied
     * @param bundle
     *            if not null then allow implicit permissions like file access
     *            to local data area
     * @return true if the permission is implied by this permissions object.
     */
    public boolean implies(Permission target, final Bundle bundle)
    {
        if (m_allPermission)
        {
            return true;
        }

        Class targetClass = target.getClass();

        cleanUp(m_queue, m_cache);

        if ((bundle != null) && targetClass == FilePermission.class)
        {
            for (int i = 0; i < m_permissionInfos.length; i++)
            {
                if (m_permissionInfos[i].getType().equals(
                    FilePermission.class.getName()))
                {
                    String postfix = "";
                    String name = m_permissionInfos[i].getName();
                    if (!"<<ALL FILES>>".equals(name))
                    {
                        if (name.endsWith("*") || name.endsWith("-"))
                        {
                            postfix = name.substring(name.length() - 1);
                            name = name.substring(0, name.length() - 1);
                        }
                        if (!(new File(name)).isAbsolute())
                        {
                            BundleContext context = (BundleContext) AccessController
                                .doPrivileged(new PrivilegedAction()
                                {
                                    public Object run()
                                    {
                                        return bundle.getBundleContext();
                                    }
                                });
                            if (context == null)
                            {
                                break;
                            }
                            name = m_action.getAbsolutePath(new File(context
                                .getDataFile(""), name));
                        }
                        if (postfix.length() > 0)
                        {
                            if ((name.length() > 0) && !name.endsWith("/"))
                            {
                                name += "/" + postfix;
                            }
                            else
                            {
                                name += postfix;
                            }
                        }
                    }
                    Permission source = createPermission(new PermissionInfo(
                        FilePermission.class.getName(), name,
                        m_permissionInfos[i].getActions()), targetClass);
                    if (source.implies(target))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        Object current = m_stack.get();

        if (current == null)
        {
            m_stack.set(targetClass);
        }
        else
        {
            if (current instanceof HashSet)
            {
                if (((HashSet) current).contains(targetClass))
                {
                    return false;
                }
                ((HashSet) current).add(targetClass);
            }
            else
            {
                if (current == targetClass)
                {
                    return false;
                }
                HashSet frame = new HashSet();
                frame.add(current);
                frame.add(targetClass);
                m_stack.set(frame);
                current = frame;
            }
        }

        try
        {
            SoftReference collectionEntry = null;

            PermissionCollection collection = null;

            synchronized (m_cache)
            {
                collectionEntry = (SoftReference) m_cache.get(targetClass);
            }

            if (collectionEntry != null)
            {
                collection = (PermissionCollection) collectionEntry.get();
            }

            if (collection == null)
            {
                collection = target.newPermissionCollection();

                if (collection == null)
                {
                    collection = new DefaultPermissionCollection();
                }

                for (int i = 0; i < m_permissionInfos.length; i++)
                {
                    PermissionInfo permissionInfo = m_permissionInfos[i];
                    String infoType = permissionInfo.getType();
                    String permissionType = targetClass.getName();

                    if (infoType.equals(permissionType))
                    {
                        Permission permission = createPermission(
                            permissionInfo, targetClass);

                        if (permission != null)
                        {
                            collection.add(permission);
                        }
                    }
                }

                synchronized (m_cache)
                {
                    m_cache.put(new Entry(target.getClass(), m_queue),
                        new SoftReference(collection));
                }
            }

            return collection.implies(target);
        }
        finally
        {
            if (current == null)
            {
                m_stack.set(null);
            }
            else
            {
                ((HashSet) current).remove(targetClass);
                if (((HashSet) current).isEmpty())
                {
                    m_stack.set(null);
                }
            }
        }
    }

    private Permission addToCache(String encoded, Permission permission)
    {
        if (permission == null)
        {
            return null;
        }

        synchronized (m_permissionCache)
        {
            Map inner = null;

            SoftReference ref = (SoftReference) m_permissionCache.get(encoded);
            if (ref != null)
            {
                inner = (Map) ref.get();
            }
            if (inner == null)
            {
                inner = new HashMap();
                m_permissionCache.put(encoded,
                    new SoftReference(inner));
            }

            inner.put(new Entry(permission.getClass()), new Entry(permission));
        }

        return permission;
    }

    private Permission getFromCache(String encoded, Class target)
    {
        synchronized (m_permissionCache)
        {
            SoftReference ref = (SoftReference) m_permissionCache.get(encoded);
            if (ref != null)
            {
                Map inner = (Map) ref.get();
                if (inner != null)
                {
                    Entry entry = (Entry) inner.get(target);
                    if (entry != null)
                    {
                        Permission result = (Permission) entry.get();
                        if (result != null)
                        {
                            return result;
                        }
                        inner.remove(entry);
                    }
                    if (inner.isEmpty())
                    {
                        m_permissionCache.remove(encoded);
                    }
                }
                else
                {
                    m_permissionCache.remove(encoded);
                }
            }

        }

        return null;
    }

    private Permission createPermission(final PermissionInfo permissionInfo,
        final Class target)
    {
        return (Permission) AccessController
            .doPrivileged(new PrivilegedAction()
            {
                public Object run()
                {
                    Permission cached = getFromCache(permissionInfo
                        .getEncoded(), target);

                    if (cached != null)
                    {
                        return cached;
                    }

                    try
                    {
                        if (m_classLoader.loadClass(target.getName()) == target)
                        {
                            return addToCache(permissionInfo.getEncoded(),
                                createPermission(permissionInfo.getName(),
                                    permissionInfo.getActions(), target));
                        }
                    }
                    catch (ClassNotFoundException e1)
                    {
                    }

                    ServiceReference[] refs = null;
                    try
                    {
                        refs = m_context.getServiceReferences(
                            PackageAdmin.class.getName(), null);
                    }
                    catch (InvalidSyntaxException e)
                    {
                    }
                    if (refs != null)
                    {
                        for (int i = 0; i < refs.length; i++)
                        {
                            PackageAdmin admin = (PackageAdmin) m_context
                                .getService(refs[i]);

                            if (admin != null)
                            {
                                Permission result = null;
                                Bundle bundle = admin.getBundle(target);
                                if (bundle != null)
                                {
                                    ExportedPackage[] exports = admin
                                        .getExportedPackages(bundle);
                                    if (exports != null)
                                    {
                                        String name = target.getName();
                                        name = name.substring(0, name
                                            .lastIndexOf('.'));

                                        for (int j = 0; j < exports.length; j++)
                                        {
                                            if (exports[j].getName().equals(
                                                name))
                                            {
                                                result = createPermission(
                                                    permissionInfo.getName(),
                                                    permissionInfo.getActions(),
                                                    target);
                                                break;
                                            }
                                        }
                                    }
                                }

                                m_context.ungetService(refs[i]);

                                return addToCache(permissionInfo.getEncoded(),
                                    result);
                            }
                        }
                    }

                    return null;
                }
            });
    }

    private Permission createPermission(String name, String action, Class target)
    {
        // System.out.println("\n\n|" + name + "|\n--\n|" + action + "|\n--\n" +
        // target + "\n\n");
        try
        {
            return (Permission) m_action.getConstructor(target,
                new Class[] { String.class, String.class }).newInstance(
                new Object[] { name, action });
        }
        catch (Exception ex)
        {
            // TODO: log this or something
        }

        return null;
    }
}
TOP

Related Classes of org.apache.felix.framework.security.util.Permissions$Entry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.