/* * Copyright (c) 2003-2007, KNOPFLERFISH project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * - Neither the name of the KNOPFLERFISH project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.knopflerfish.service.um.useradmin.impl; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.AccessController; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import org.knopflerfish.service.um.useradmin.Condition; import org.osgi.framework.Bundle; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.event.EventAdmin; import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.User; import org.osgi.service.useradmin.UserAdmin; import org.osgi.service.useradmin.UserAdminEvent; import org.osgi.service.useradmin.UserAdminListener; import org.osgi.service.useradmin.UserAdminPermission; import org.osgi.util.tracker.ServiceTracker; /** * Implementation of UserAdmin. * * @author Gatespace AB * @version $Revision: 1.1.1.1 $ */ public class UserAdminImpl implements ServiceFactory, UserAdmin, ServiceListener { static final UserAdminPermission adminPermission; protected ServiceReference uasr; // our service ref protected Hashtable /* String -> RoleImpl */roles; // role db protected Vector /* ServiceReferences */listeners; // UserAdminListener:s RoleImpl anyone; // predefined role EventQueue eventQueue; ServiceTracker eventAdminTracker; static { adminPermission = new UserAdminPermission(UserAdminPermission.ADMIN, null); } UserAdminImpl() { revert(); // Read saved roles if (roles == null) { zap(); // Create "empty" roles table } listeners = new Vector(); eventAdminTracker = new ServiceTracker(Activator.bc, EventAdmin.class.getName(), null ); eventQueue = new EventQueue(Activator.bc); } /** * Initialization method for the user admin. We must wait for the service * reference before we can check out UserAdminListeners. * * @param sr * service reference for UserAdmin. */ private void init(ServiceReference sr) { this.uasr = sr; // Listen for UserAdminListeners, collect those already registered try { String clazz = UserAdminListener.class.getName(); Activator.bc.addServiceListener(this, "(objectClass=" + clazz + ")"); ServiceReference[] srs = Activator.bc.getServiceReferences(clazz, null); if (srs != null) { for (int i = 0; i < srs.length; i++) { listeners.addElement(srs[i]); if (Activator.log.doDebug()) Activator.log.debug("UserAdminListener found: " + srs[i]); } } } catch (InvalidSyntaxException ex) { } eventAdminTracker.open(); if (Activator.log.doInfo()) Activator.log.info("Service initialized", uasr); } /** * The bundle owning this service is stopping; terminate the worker * thread. */ void stop() { save(); // Try to save roles table } /** * Sends an event to all user admin listeners. * * @param type * the event type, one of UserAdminEvent.ROLE_CHANGED * .ROLE_CREATED or .ROLE_REMOVED. * @param role * the role that the event is generated for. */ void sendEvent(int type, Role role) { // dont send event if type = CHANGED and role has been removed if (!(type == UserAdminEvent.ROLE_CHANGED && roles.get(role.getName()) == null)) { UserAdminEvent event = new UserAdminEvent(uasr, type, role); eventQueue.enqueue( new SendUserAdminEventJob(Activator.bc, eventAdminTracker, event, listeners) ); if (Activator.log.doDebug()) Activator.log.debug(event.toString(), uasr); } else { if (Activator.log.doDebug()) Activator.log.debug("Event not sent, " + role.getName() + " has been removed.", uasr); } } // - interface org.osgi.framework.ServiceFactory // ---------------------------- public synchronized Object getService(Bundle bundle, ServiceRegistration registration) { // Factory is only used to be able to register and then later // get hold of our own ServiceReference before any bundle have // a chance to use the service. if (uasr == null) { // initialize ourself with the service reference the first time // the service is used by a bundle init(registration.getReference()); } return this; } public void ungetService(Bundle bundle, ServiceRegistration registration, java.lang.Object service) { } // - interface org.osgi.service.useradmin.UserAdmin // ------------------------- public Role createRole(String name, int type) { SecurityManager sm = System.getSecurityManager(); if(null!=sm){ sm.checkPermission(adminPermission); } if (roles.get(name) != null) { // role 'name' already exists, abort and return null return null; } Role role; switch (type) { case Role.USER: role = new UserImpl(name); break; case Role.GROUP: role = new GroupImpl(name); break; case Condition.CONDITION: role = new ConditionImpl(name); break; default: throw new IllegalArgumentException("UserAdminImpl: Unknown type '" + type + "'."); } roles.put(name, role); sendEvent(UserAdminEvent.ROLE_CREATED, role); return role; } public boolean removeRole(String name) { SecurityManager sm = System.getSecurityManager(); if(null!=sm){ sm.checkPermission(adminPermission); } if (Role.USER_ANYONE.equals(name)) { // not OK to remove the predefined role return false; } RoleImpl role = (RoleImpl) roles.remove(name); if (role != null) { role.remove(); sendEvent(UserAdminEvent.ROLE_REMOVED, role); return true; } return false; } public Role getRole(String name) { return (Role) roles.get(name); } public Role[] getRoles(String filter) throws InvalidSyntaxException { Vector v = new Vector(); for (Enumeration en = roles.elements(); en.hasMoreElements();) { RoleImpl role = (RoleImpl) en.nextElement(); if (filter == null || LDAPQuery.query(filter, role.getProperties())) { v.addElement(role); } } Role[] result = new Role[v.size()]; v.copyInto(result); return result; } public User getUser(String key, String value) { User[] users = getUsers(key, value); return users.length == 1 ? users[0] : null; } private User[] getUsers(String key, String value) { Vector found = new Vector(); for (Enumeration en = roles.elements(); en.hasMoreElements();) { Object o = en.nextElement(); if (o instanceof UserImpl) { UserImpl user = (UserImpl) o; Object val = user.getProperties().get(key); if (val instanceof String && value.equals(val)) { found.addElement(user); } } } User[] result = new User[found.size()]; found.copyInto(result); return result; } public Authorization getAuthorization(User user) { RoleImpl role = user != null ? (UserImpl) user : anyone; return new AuthorizationImpl(role); } // - interface org.osgi.framework.ServiceListener -------------------------- public void serviceChanged(ServiceEvent event) { ServiceReference sr = event.getServiceReference(); switch (event.getType()) { case ServiceEvent.REGISTERED: listeners.addElement(sr); if (Activator.log.doDebug()) Activator.log.debug("UserAdminListener found: " + sr); break; case ServiceEvent.UNREGISTERING: if (listeners.removeElement(sr) && Activator.log.doDebug()) Activator.log.debug("UserAdminListener gone: " + sr); break; } } // remove contents of roles protected void zap() { roles = new Hashtable(); // create the special roles (no events for these) roles.put(Role.USER_ANYONE, anyone = new RoleImpl(Role.USER_ANYONE)); } // Revert to the saved state protected void revert() { if (Boolean.getBoolean("org.knopflerfish.useradmin.dontsave")) { if (Activator.log.doDebug()) Activator.log.debug("read skipped"); return; } String path = System.getProperty("org.knopflerfish.useradmin.store"); String oldPath = System.getProperty("org.knopflerfish.useradmin.oldstore"); File file; if (path == null) { file = Activator.bc.getDataFile("ua_store"); } else { file = new File(path); if (file == null || !file.exists()) { file = new File(oldPath); } } try { if (file != null && file.exists()) { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); Object obj = ois.readObject(); ois.close(); if (obj instanceof Hashtable) { roles = (Hashtable) obj; if (Activator.log.doDebug()) Activator.log.debug("roles reverted"); } else { Activator.log.error("ua_store corrupted"); } } else { if (Activator.log.doDebug()) Activator.log.debug("ua_store not found"); } } catch (ClassNotFoundException e) { Activator.log.error("Failed to instantiate saved roles", e); } catch (IOException e) { Activator.log.error("Failed to read saved roles", e); } } // Save the current state protected void save() { if (Boolean.getBoolean("org.knopflerfish.useradmin.dontsave")) { if (Activator.log.doDebug()) Activator.log.debug("save skipped"); return; } String path = System.getProperty("org.knopflerfish.useradmin.store"); File file; if (path == null) { file = Activator.bc.getDataFile("ua_store"); if (file == null) { Activator.log.info("The platform cannot provide a data file. Cannot save roles."); return; } } else { file = new File(path); } try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(roles); oos.close(); } catch (IOException e) { Activator.log.error("Failed to save roles", e); } } }