/* * 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.eventadmin.impl.security; import java.security.Permission; import org.osgi.framework.Bundle; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; /** * This class is a decorator for an <tt>EventAdmin</tt> service. It secures the * service by checking any call from a given bundle (i.e., the caller) to the admins * post or send methods for the appropriate permissions based on a given permission * factory. This methods then in turn throw a <tt>SecurityException</tt> in case * the given bundle doesn't pass the check or delegate the call to decorated service * instance, respectively. * * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class EventAdminSecurityDecorator implements EventAdmin { // The bundle used to determine appropriate permissions private final Bundle m_bundle; // The decorated service instance private final EventAdmin m_admin; /** * The constructor of this decorator. The given bundle and permission factory * will be used to determine appropriate permissions for any call to * <tt>postEvent()</tt> or <tt>sendEvent()</tt>, respectively. This method then * in turn throw a <tt>SecurityException</tt> in case the given bundle doesn't * pass the check. * * @param bundle The calling bundle used to determine appropriate permissions * @param admin The decorated service instance */ public EventAdminSecurityDecorator(final Bundle bundle, final EventAdmin admin) { checkNull(bundle, "Bundle"); checkNull(admin, "Admin"); m_bundle = bundle; m_admin = admin; } /** * This method checks whether the given (i.e., calling) bundle has * appropriate permissions to post an event to the targeted topic. A * <tt>SecurityException</tt> is thrown in case it has not. Otherwise, the * event is posted using this decorator's service instance. * * @param event The event that should be posted * * @see org.osgi.service.event.EventAdmin#postEvent(org.osgi.service.event.Event) */ public void postEvent(final Event event) { checkPermission(event.getTopic()); m_admin.postEvent(event); } /** * This method checks whether the given (i.e., calling) bundle has * appropriate permissions to send an event to the targeted topic. A * <tt>SecurityException</tt> is thrown in case it has not. Otherwise, * the event is posted using this decorator's service instance. * * @param event The event that should be send * * @see org.osgi.service.event.EventAdmin#sendEvent(org.osgi.service.event.Event) */ public void sendEvent(final Event event) { checkPermission(event.getTopic()); m_admin.sendEvent(event); } /** * Overrides <tt>hashCode()</tt> and returns the hash code of the decorated * service instance. * * @return The hash code of the decorated service instance * * @see java.lang.Object#hashCode() * @see org.osgi.service.event.EventAdmin */ public int hashCode() { return m_admin.hashCode(); } /** * Overrides <tt>equals()</tt> and delegates the call to the decorated service * instance. In case that o is an instance of this class it passes o's service * instance instead of o. * * @param o The object to compare with this decorator's service instance * * @see java.lang.Object#equals(java.lang.Object) * @see org.osgi.service.event.EventAdmin */ public boolean equals(final Object o) { if(o instanceof EventAdminSecurityDecorator) { return m_admin.equals(((EventAdminSecurityDecorator) o).m_admin); } return m_admin.equals(o); } /** * This is a utility method that will throw a <tt>SecurityExcepiton</tt> in case * that the given bundle (i.e, the caller) has not appropriate permissions to * publish to this topic. This method uses Bundle.hasPermission() and the given * permission factory to determine this. */ private void checkPermission(final String topic) { final Permission p = PermissionsUtil.createPublishPermission(topic); if(p != null && !m_bundle.hasPermission(p)) { throw new SecurityException("Bundle[" + m_bundle + "] has no PUBLISH permission for topic [" + topic + "]"); } } /* * This is a utility method that will throw a <tt>NullPointerException</tt> * in case that the given object is null. The message will be of the form name + * may not be null. */ private void checkNull(final Object object, final String name) { if(null == object) { throw new NullPointerException(name + " may not be null"); } } }