Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjfogell2005-12-15 20:26:41 +0000
committerjfogell2005-12-15 20:26:41 +0000
commit66912d73ac981e71e819588f89f28fd0ec74049a (patch)
treef5ca7b4ee57a966e63d973e5d2e6e7de2ca6d55f /bundles/org.eclipse.equinox.useradmin/src
parent83fbd37f24c5aa8b0931b62d6da9cfb838970d62 (diff)
downloadrt.equinox.bundles-66912d73ac981e71e819588f89f28fd0ec74049a.tar.gz
rt.equinox.bundles-66912d73ac981e71e819588f89f28fd0ec74049a.tar.xz
rt.equinox.bundles-66912d73ac981e71e819588f89f28fd0ec74049a.zip
initial checkin for OSGi User Admin Service
Diffstat (limited to 'bundles/org.eclipse.equinox.useradmin/src')
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Activator.java109
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Authorization.java148
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/ExternalMessages.properties32
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Group.java296
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTracker.java150
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTrackerMsg.java27
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Role.java137
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/User.java144
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdmin.java355
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminEventProducer.java141
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminHashtable.java173
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminMsg.java38
-rw-r--r--bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminStore.java348
13 files changed, 2098 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Activator.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Activator.java
new file mode 100644
index 000000000..d29ce6efd
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Activator.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.util.Hashtable;
+import org.osgi.framework.*;
+import org.osgi.service.prefs.PreferencesService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/** This is the bundle activator for the UserAdmin bundle.
+ */
+
+public class Activator implements BundleActivator, ServiceFactory, ServiceTrackerCustomizer {
+ /*
+ * ----------------------------------------------------------------------
+ * BundleActivator Interface implementation
+ * ----------------------------------------------------------------------
+ */
+
+ protected ServiceRegistration registration;
+ protected UserAdmin userAdmin;
+ protected static String userAdminClazz = "org.osgi.service.useradmin.UserAdmin"; //$NON-NLS-1$
+ protected PreferencesService prefs;
+ protected BundleContext context;
+ protected ServiceTracker prefsTracker;
+
+ /** Need to have a public default constructor so that the BundleActivator
+ * can be instantiated by Class.newInstance().
+ */
+ public Activator() {
+ }
+
+ /**
+ * Required by BundleActivator Interface.
+ */
+ public void start(BundleContext context) throws Exception {
+ this.context = context;
+ prefsTracker = new ServiceTracker(context, PreferencesService.class.getName(), this);
+ prefsTracker.open();
+ }
+
+ /**
+ * Required by BundleActivator Interface.
+ */
+ public void stop(BundleContext context) throws Exception {
+ prefsTracker.close();
+ registration.unregister();
+ userAdmin.destroy();
+ userAdmin = null;
+ }
+
+ /**
+ * Register the UserAdmin service.
+ */
+ protected void registerUserAdminService() throws Exception {
+ Hashtable properties = new Hashtable(7);
+
+ properties.put(Constants.SERVICE_VENDOR, UserAdminMsg.Service_Vendor);
+ properties.put(Constants.SERVICE_DESCRIPTION, UserAdminMsg.OSGi_User_Admin_service_IBM_Implementation_3);
+ properties.put(Constants.SERVICE_PID, getClass().getName());
+
+ userAdmin = new UserAdmin(prefs, context);
+ registration = context.registerService(userAdminClazz, this, properties);
+ userAdmin.setServiceReference(registration.getReference());
+ }
+
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ userAdmin.setServiceReference(registration.getReference());
+
+ return userAdmin;
+ }
+
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ }
+
+ public Object addingService(ServiceReference reference) {
+ if (prefs == null) {
+ prefs = (PreferencesService) context.getService(reference);
+ try {
+ registerUserAdminService();
+ } catch (Exception ex) {
+ return null;
+ }
+ return prefs;
+ }
+ return null; //we don't want to track a service we are not using
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ if (service == prefs) {
+ prefs = null;
+ }
+ registration.unregister();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Authorization.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Authorization.java
new file mode 100644
index 000000000..614db7d20
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Authorization.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.util.Vector;
+
+/**
+ * This interface encapsulates an authorization context on which bundles
+ * can base authorization decisions where appropriate.
+ * <p>
+ * Bundles associate the privilege to access restricted resources or
+ * operations with roles. Before granting access to a restricted resource
+ * or operation, a bundle will check if the Authorization object passed
+ * to it possesses the required role, by calling its hasRole method.
+ * <p>
+ * Authorization contexts are instantiated by calling
+ * {@link UserAdmin#getAuthorization}
+ * <p>
+ * <font size="+1">Trusting Authorization objects.</font>
+ * <p>
+ * There are no restrictions regarding the creation of Authorization objects.
+ * Hence, a service must only accept Authorization objects from bundles that
+ * has been authorized to use the service using code based (or Java 2)
+ * permissions.
+ * <p>
+ * In some cases it is useful to use ServicePermissions to do the code based
+ * access control. A service basing user access control on Authorization
+ * objects passed to it, will then require that a calling bundle has the
+ * ServicePermission to get the service in question. This is the most
+ * convenient way. The framework will do the code based permission check
+ * when the calling bundle attempts to get the service from the service
+ * registry.
+ * <p>
+ * Example: A servlet using a service on a user's behalf. The bundle with the
+ * servlet must be given the ServicePermission to get the Service.
+ * <p>
+ * However, in some cases the code based permission checks need to be more
+ * fine-grained. A service might allow all bundles to get it, but
+ * require certain code based permissions for some of its methods.
+ * <p>
+ * Example: A servlet using a service on a user's behalf, where some
+ * service functionality is open to anyone, and some is restricted by code
+ * based permissions. When a restricted method is called
+ * (e.g., one handing over
+ * an Authorization object), the service explicitly checks that the calling
+ * bundle has permission to make the call.
+ */
+public class Authorization implements org.osgi.service.useradmin.Authorization {
+
+ protected UserAdmin useradmin;
+ protected Role user;
+ protected String name; //user to distinguish between the anonymous user and user.anyone
+
+ protected Authorization(User user, UserAdmin useradmin) {
+ this.useradmin = useradmin;
+ if (user != null) {
+ this.user = user;
+ name = user.getName();
+ } else {
+ //anonymous user
+ this.user = (Role) useradmin.getRole(Role.anyoneString);
+ name = null;
+ }
+ }
+
+ /**
+ * Gets the name of the {@link User} that this Authorization
+ * context was created for.
+ *
+ * @return The name of the {@link User} that this Authorization
+ * context was created for, or <code>null</code> if no user was specified
+ * when this Authorization context was created.
+ */
+ public String getName() {
+ useradmin.checkAlive();
+ return (name);
+ }
+
+ /**
+ * Checks if the role with the specified name is implied by this
+ * Authorization context.
+ * <p>
+
+ * Bundles must define globally unique role names that are associated with
+ * the privilege of accessing restricted resources or operations.
+ * System administrators will grant users access to these resources, by
+ * creating a {@link Group} for each role and adding {@link User}s to it.
+ *
+ * @param name The name of the role to check for.
+ *
+ * @return <code>true</code> if this Authorization context implies the
+ * specified role, otherwise <code>false</code>.
+ */
+ public boolean hasRole(String name) {
+ useradmin.checkAlive();
+ synchronized (useradmin) {
+ Role checkRole = (org.eclipse.equinox.useradmin.Role) useradmin.getRole(name);
+ if (checkRole == null) {
+ return (false);
+ }
+ return (checkRole.isImpliedBy(user, new Vector()));
+ }
+ }
+
+ /**
+ * Gets the names of all roles encapsulated by this Authorization context.
+ *
+ * @return The names of all roles encapsulated by this Authorization
+ * context, or <code>null</code> if no roles are in the context.
+ */
+ public String[] getRoles() {
+ useradmin.checkAlive();
+
+ // go through all of the roles and find out which ones are implied by this
+ // authorization context.
+ synchronized (useradmin) //we don't want anything changing while we get the list
+ {
+ int length = useradmin.roles.size();
+ Vector result = new Vector(length);
+ for (int i = 0; i < length; i++) {
+ Role role = (Role) useradmin.roles.elementAt(i);
+ if (role.isImpliedBy(user, new Vector())) {
+ String name = role.getName();
+ //exclude user.anyone from the list
+ if (!name.equals(Role.anyoneString))
+ {
+ result.addElement(name);
+ }
+ }
+ }
+ int size = result.size();
+ if (size == 0) {
+ return (null);
+ }
+ String[] copyrole = new String[size];
+ result.copyInto(copyrole);
+ return (copyrole);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/ExternalMessages.properties b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/ExternalMessages.properties
new file mode 100644
index 000000000..386f94669
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/ExternalMessages.properties
@@ -0,0 +1,32 @@
+###############################################################################
+# Copyright (c) 2001, 2005 IBM Corporation.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+# NLS_MESSAGEFORMAT_ALL
+
+OSGi_User_Admin_service_IBM_Implementation_3=OSGi User Admin service - IBM Implementation
+Service_Vendor=IBM
+adding_Credential_to__15=adding Credential to {0}
+adding_member__18=adding member {0} to group {1}
+adding_required_member__21=adding required member {0} to group {1}
+removing_member__24=removing member {0} from group {1}
+Unable_to_load_role__27=Unable to load role {0}
+Backing_Store_Read_Exception=UserAdmin is unable to read its data from backing store {0}
+Backing_Store_Write_Exception=UserAdmin is unable to write its data from backing store {0}
+Event_Delivery_Exception=A UserAdminListener threw an Exception
+CREATE_NULL_ROLE_EXCEPTION =Role can not be null
+CREATE_INVALID_TYPE_ROLE_EXCEPTION=Invalid type for createRole
+INVALID_KEY_EXCEPTION=Key can only be of type String
+INVALID_VALUE_EXCEPTION=Value can only be of type String or byte[]
+USERADMIN_UNREGISTERED_EXCEPTION=UserAdmin service has been unregistered
+
+Unknown_Log_level=Unknown Log Level
+Info=Log Info
+Warning=Log Warning
+Error=Log Error \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Group.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Group.java
new file mode 100644
index 000000000..224659f59
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Group.java
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+ * A named grouping of roles.
+ * <p>
+ * Whether or not a given authorization context implies a Group role
+ * depends on the members of that role.
+ * <p>
+ * A Group role can have two kinds of member roles: <i>basic</i> and
+ * <i>required</i>.
+ * A Group role is implied by an authorization context if all of
+ * its required member roles are implied
+ * and at least one of its basic member roles is implied.
+ * <p>
+ * A Group role must contain at least one basic member role in order
+ * to be implied. In other words, a Group without any basic member
+ * roles is never implied by any authorization context.
+ * <p>
+ * A User role always implies itself.
+ * <p>
+ * No loop detection is performed when adding members to groups, which
+ * means that it is possible to create circular implications. Loop
+ * detection is instead done when roles are checked. The semantics is that
+ * if a role depends on itself (i.e., there is an implication loop), the
+ * role is not implied.
+ * <p>
+ * The rule that a group must have at least one basic member to be implied
+ * is motivated by the following example:
+ *
+ * <pre>
+ * group foo
+ * required members: marketing
+ * basic members: alice, bob
+ * </pre>
+ *
+ * Privileged operations that require membership in "foo" can be performed
+ * only by alice and bob, who are in marketing.
+ * <p>
+ * If alice and bob ever transfer to a different department, anybody in
+ * marketing will be able to assume the "foo" role, which certainly must be
+ * prevented.
+ * Requiring that "foo" (or any Group role for that matter) must have at least
+ * one basic member accomplishes that.
+ * <p>
+ * However, this would make it impossible for a group to be implied by just
+ * its required members. An example where this implication might be useful
+ * is the following declaration: "Any citizen who is an adult is allowed to
+ * vote."
+ * An intuitive configuration of "voter" would be:
+ *
+ * <pre>
+ * group voter
+ * required members: citizen, adult
+ * basic members:
+ * </pre>
+ *
+ * However, according to the above rule, the "voter" role could never be
+ * assumed by anybody, since it lacks any basic members.
+ * In order to address this deficiency a predefined role named
+ * "user.anyone" can be specified, which is always implied.
+ * The desired implication of the "voter" group can then be achieved by
+ * specifying "user.anyone" as its basic member, as follows:
+ *
+ * <pre>
+ * group voter
+ * required members: citizen, adult
+ * basic members: user.anyone
+ * </pre>
+ */
+
+public class Group extends User implements org.osgi.service.useradmin.Group {
+
+ protected Vector requiredMembers;
+ protected Vector basicMembers;
+ protected UserAdmin useradmin;
+
+ protected Group(String name, UserAdmin useradmin) {
+ super(name, useradmin);
+ this.useradmin = useradmin;
+ basicMembers = new Vector();
+ requiredMembers = new Vector();
+ }
+
+ /**
+ * Adds the specified role as a basic member to this Group.
+ *
+ * @param role The role to add as a basic member.
+ *
+ * @return <code>true</code> if the given role could be added as a basic
+ * member,
+ * and <code>false</code> if this Group already contains a role whose name
+ * matches that of the specified role.
+ *
+ * @throws SecurityException If a security manager exists and the caller
+ * does not have the <tt>UserAdminPermission</tt> with name <tt>admin</tt>.
+ */
+ public boolean addMember(org.osgi.service.useradmin.Role role) {
+ useradmin.checkAlive();
+ useradmin.checkAdminPermission();
+ //only need to check for null for the public methods
+ if (role == null) {
+ return (false);
+ }
+ synchronized (useradmin) {
+ if (basicMembers.contains(role)) {
+ return (false);
+ }
+ return (addMember(role, true));
+ }
+ }
+
+ // When we are loading from storage this method is called directly. We
+ // do not want to write to storage when we are loading form storage.
+ protected boolean addMember(org.osgi.service.useradmin.Role role, boolean store) {
+ ((org.eclipse.equinox.useradmin.Role) role).addImpliedRole(this);
+ if (store) {
+ try {
+ useradmin.userAdminStore.addMember(this, (org.eclipse.equinox.useradmin.Role) role);
+ } catch (BackingStoreException ex) {
+ return (false);
+ }
+ }
+ basicMembers.addElement(role);
+ return (true);
+ }
+
+ /**
+ * Adds the specified role as a required member to this Group.
+ *
+ * @param role The role to add as a required member.
+ *
+ * @return <code>true</code> if the given role could be added as a required
+ * member, and <code>false</code> if this Group already contains a role
+ * whose name matches that of the specified role.
+ *
+ * @throws SecurityException If a security manager exists and the caller
+ * does not have the <tt>UserAdminPermission</tt> with name <tt>admin</tt>.
+ */
+ public boolean addRequiredMember(org.osgi.service.useradmin.Role role) {
+ useradmin.checkAlive();
+ useradmin.checkAdminPermission();
+ if (role == null) {
+ return (false);
+ }
+ synchronized (useradmin) {
+ if (requiredMembers.contains(role)) {
+ return (false);
+ }
+ return (addRequiredMember(role, true));
+ }
+ }
+
+ protected boolean addRequiredMember(org.osgi.service.useradmin.Role role, boolean store) {
+ ((org.eclipse.equinox.useradmin.Role) role).addImpliedRole(this);
+ if (store) {
+ try {
+ useradmin.userAdminStore.addRequiredMember(this, (org.eclipse.equinox.useradmin.Role) role);
+ } catch (BackingStoreException ex) {
+ return (false);
+ }
+ }
+ requiredMembers.addElement(role);
+ return (true);
+ }
+
+ /**
+ * Removes the specified role from this Group.
+ *
+ * @param role The role to remove from this Group.
+ *
+ * @return <code>true</code> if the role could be removed,
+ * otherwise <code>false</code>.
+ *
+ * @throws SecurityException If a security manager exists and the caller
+ * does not have the <tt>UserAdminPermission</tt> with name <tt>admin</tt>.
+ */
+ public boolean removeMember(org.osgi.service.useradmin.Role role) {
+ useradmin.checkAlive();
+ useradmin.checkAdminPermission();
+ if (role == null) {
+ return (false);
+ }
+ synchronized (useradmin) {
+ try {
+ useradmin.userAdminStore.removeMember(this, (org.eclipse.equinox.useradmin.Role) role);
+ } catch (BackingStoreException ex) {
+ return (false);
+ }
+ //The role keeps track of which groups it is a member of so it can remove itself from
+ //the group if it is deleted. In this case, this group is being removed from the role's
+ //list.
+ ((org.eclipse.equinox.useradmin.Role) role).removeImpliedRole(this);
+
+ // We don't know if the Role to be removed is a basic orrequired member, or both. We
+ // simply try to remove it from both.
+ boolean removeRequired = requiredMembers.removeElement(role);
+ boolean removeBasic = basicMembers.removeElement(role);
+ return (removeRequired || removeBasic);
+ }
+ }
+
+ /**
+ * Gets the basic members of this Group.
+ *
+ * @return The basic members of this Group, or <code>null</code> if this
+ * Group does not contain any basic members.
+ */
+ public org.osgi.service.useradmin.Role[] getMembers() {
+ useradmin.checkAlive();
+ synchronized (useradmin) {
+ if (basicMembers.isEmpty()) {
+ return (null);
+ }
+ Role[] roles = new Role[basicMembers.size()];
+ basicMembers.copyInto(roles);
+ return (roles);
+ }
+ }
+
+ /**
+ * Gets the required members of this Group.
+ *
+ * @return The required members of this Group, or <code>null</code> if this
+ * Group does not contain any required members.
+ */
+ public org.osgi.service.useradmin.Role[] getRequiredMembers() {
+ useradmin.checkAlive();
+ synchronized (useradmin) {
+ if (requiredMembers.isEmpty()) {
+ return (null);
+ }
+ Role[] roles = new Role[requiredMembers.size()];
+ requiredMembers.copyInto(roles);
+ return (roles);
+ }
+ }
+
+ /**
+ * Returns the type of this role.
+ *
+ * @return The role's type.
+ */
+ public int getType() {
+ useradmin.checkAlive();
+ return (Role.GROUP);
+ }
+
+ protected boolean isImpliedBy(Role role, Vector checkLoop) {
+ if (checkLoop.contains(name)) {
+ //we have a circular dependency
+ return (false);
+ }
+ if (name.equals(role.getName())) //A User always implies itself. A Group is a User.
+ {
+ return (true);
+ }
+ checkLoop.addElement(name);
+ Vector requiredCheckLoop = (Vector) checkLoop.clone();
+ Vector basicCheckLoop = (Vector) checkLoop.clone();
+ Enumeration e = requiredMembers.elements();
+
+ //check to see if we imply all of the 0 or more required roles
+ Role requiredRole;
+ while (e.hasMoreElements()) {
+ requiredRole = (Role) e.nextElement();
+ if (!requiredRole.isImpliedBy(role, requiredCheckLoop)) {
+ return (false);
+ }
+ }
+ //check to see if we imply any of the basic roles (there must be at least one)
+ e = basicMembers.elements();
+ Role basicRole;
+ while (e.hasMoreElements()) {
+ basicRole = (Role) e.nextElement();
+ if (basicRole.isImpliedBy(role, basicCheckLoop)) {
+ return (true);
+ }
+ }
+ return (false);
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTracker.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTracker.java
new file mode 100644
index 000000000..74b43be51
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTracker.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.util.Calendar;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * LogTracker class. This class encapsulates the LogService
+ * and handles all issues such as the service coming and going.
+ */
+
+public class LogTracker extends ServiceTracker implements LogService {
+ /** LogService interface class name */
+ protected final static String clazz = "org.osgi.service.log.LogService"; //$NON-NLS-1$
+
+ /** PrintStream to use if LogService is unavailable */
+ protected PrintStream out;
+
+ /** Calendar and DateFormat to user if LogService is unavailable */
+ private static Calendar calendar;
+ private static DateFormat dateFormat;
+ private String timestamp;
+
+ /**
+ * Create new LogTracker.
+ *
+ * @param context BundleContext of parent bundle.
+ * @param out Default PrintStream to use if LogService is unavailable.
+ */
+ public LogTracker(BundleContext context, PrintStream out) {
+ super(context, clazz, null);
+ this.out = out;
+ calendar = Calendar.getInstance();
+ dateFormat = DateFormat.getDateTimeInstance();
+ open();
+ }
+
+ /*
+ * ----------------------------------------------------------------------
+ * LogService Interface implementation
+ * ----------------------------------------------------------------------
+ */
+
+ public void log(int level, String message) {
+ log(null, level, message, null);
+ }
+
+ public void log(int level, String message, Throwable exception) {
+ log(null, level, message, exception);
+ }
+
+ public void log(ServiceReference reference, int level, String message) {
+ log(reference, level, message, null);
+ }
+
+ public synchronized void log(ServiceReference reference, int level, String message, Throwable exception) {
+ ServiceReference[] references = getServiceReferences();
+
+ if (references != null) {
+ int size = references.length;
+
+ for (int i = 0; i < size; i++) {
+ LogService service = (LogService) getService(references[i]);
+ if (service != null) {
+ try {
+ service.log(reference, level, message, exception);
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ return;
+ }
+
+ noLogService(level, message, exception, reference);
+ }
+
+ /**
+ * The LogService is not available so we write the message to a PrintStream.
+ *
+ * @param level Logging level
+ * @param message Log message.
+ * @param throwable Log exception or null if none.
+ * @param reference ServiceReference associated with message or null if none.
+ */
+ protected void noLogService(int level, String message, Throwable throwable, ServiceReference reference) {
+ if (out != null) {
+ synchronized (out) {
+ // Bug #113286. If no log service present and messages are being
+ // printed to stdout, prepend message with a timestamp.
+ timestamp = dateFormat.format(calendar.getTime());
+ out.print(timestamp + " "); //$NON-NLS-1$
+
+ switch (level) {
+ case LOG_DEBUG : {
+ out.print("Debug: "); //$NON-NLS-1$
+
+ break;
+ }
+ case LOG_INFO : {
+ out.print(LogTrackerMsg.Info);
+
+ break;
+ }
+ case LOG_WARNING : {
+ out.print(LogTrackerMsg.Warning);
+
+ break;
+ }
+ case LOG_ERROR : {
+ out.print(LogTrackerMsg.Error);
+
+ break;
+ }
+ default : {
+ out.print("["); //$NON-NLS-1$
+ out.print(LogTrackerMsg.Unknown_Log_level);
+ out.print("]: "); //$NON-NLS-1$
+
+ break;
+ }
+ }
+
+ out.println(message);
+
+ if (reference != null) {
+ out.println(reference);
+ }
+
+ if (throwable != null) {
+ throwable.printStackTrace(out);
+ }
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTrackerMsg.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTrackerMsg.java
new file mode 100644
index 000000000..127910bad
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/LogTrackerMsg.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import org.eclipse.osgi.util.NLS;
+
+public class LogTrackerMsg extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.useradmin.ExternalMessages"; //$NON-NLS-1$
+
+ public static String Unknown_Log_level;
+ public static String Info;
+ public static String Warning;
+ public static String Error;
+
+ static {
+ // initialize resource bundles
+ NLS.initializeMessages(BUNDLE_NAME, LogTrackerMsg.class);
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Role.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Role.java
new file mode 100644
index 000000000..195407bc6
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/Role.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.util.*;
+
+/**
+ * The base interface for Role objects managed by the {@link UserAdmin}
+ * service.
+ * <p>
+ * This interface exposes the characteristics shared by all Roles: a name,
+ * a type, and a set of properties.
+ * <p>
+ * Properties represent public information about the Role that can be read by
+ * anyone. Specific {@link UserAdminPermission}s are required to
+ * change a Role's properties.
+ * <p>
+ * Role properties are Dictionary objects. Changes to
+ * these objects are propagated to the {@link UserAdmin} service and
+ * made persistent.
+ * <p>
+ * Every UserAdmin contains a set of predefined roles that are always present
+ * and cannot be removed. All predefined roles are of type <tt>ROLE</tt>.
+ * This version of the <tt>org.osgi.service.useradmin</tt> package defines a
+ * single predefined role named &quot;user.anyone&quot;, which is inherited
+ * by any other role. Other predefined roles may be added in the future.
+ */
+
+public class Role implements org.osgi.service.useradmin.Role {
+
+ protected String name;
+ protected UserAdminHashtable properties;
+ protected Vector impliedRoles;
+ protected UserAdmin useradmin;
+ protected static final String anyoneString = "user.anyone"; //$NON-NLS-1$
+ protected boolean exists = true;
+
+ protected Role(String name, UserAdmin useradmin) {
+ this.name = name;
+ this.properties = new UserAdminHashtable(this, useradmin, UserAdminHashtable.PROPERTIES);
+ this.useradmin = useradmin;
+
+ // This is used only to track which Groups this role is directly a member of.
+ // This info is needed so when we delete a Role, we know which groups to remove
+ // it from.
+ impliedRoles = new Vector();
+ }
+
+ /**
+ * Returns the name of this role.
+ *
+ * @return The role's name.
+ */
+
+ public String getName() {
+ useradmin.checkAlive();
+ return (name);
+ }
+
+ /**
+ * Returns the type of this role.
+ *
+ * @return The role's type.
+ */
+ public int getType() {
+ useradmin.checkAlive();
+ return (Role.ROLE);
+ }
+
+ /**
+ * Returns a Dictionary of the (public) properties of this Role. Any changes
+ * to the returned Dictionary will change the properties of this Role. This
+ * will cause a UserAdminEvent of type {@link UserAdminEvent#ROLE_CHANGED}
+ * to be broadcast to any UserAdminListeners.
+ * <p>
+ * Only objects of type <tt>String</tt> may be used as property keys, and
+ * only objects of type <tt>String</tt> or <tt>byte[]</tt>
+ * may be used as property values.
+ * Any other types will cause an exception of type
+ * <tt>IllegalArgumentException</tt> to be raised.
+ * <p>
+ * In order to add, change, or remove a property in the returned Dictionary,
+ * a {@link UserAdminPermission} named after the property name (or
+ * a prefix of it) with action <code>changeProperty</code> is required.
+ *
+ * @return Dictionary containing the properties of this Role.
+ */
+ public Dictionary getProperties() {
+ useradmin.checkAlive();
+ return (properties);
+ }
+
+ protected void addImpliedRole(Group group) {
+ impliedRoles.addElement(group);
+ }
+
+ protected void removeImpliedRole(Group group) {
+ if (exists) //this prevents a loop when destroy is called
+ {
+ impliedRoles.removeElement(group);
+ }
+ }
+
+ //we are being deleted so delete ourselves from all of the groups
+ protected synchronized void destroy() {
+ exists = false;
+ Enumeration e = impliedRoles.elements();
+ while (e.hasMoreElements()) {
+ Group group = (Group) e.nextElement();
+ if (group.exists) //so we don't try to remove any groups twice from storage
+ {
+ group.removeMember(this);
+ }
+ }
+ properties = null;
+ impliedRoles = null;
+ }
+
+ protected boolean isImpliedBy(Role role, Vector checkLoop) { //Roles do not imply themselves
+ //The user.anyone role is always implied
+ if (checkLoop.contains(name)) {
+ //we have a circular dependency
+ return (false);
+ }
+ checkLoop.addElement(name);
+ return (name.equals(Role.anyoneString));
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/User.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/User.java
new file mode 100644
index 000000000..025773a91
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/User.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.util.Dictionary;
+import java.util.Vector;
+
+/**
+ * A User managed by a {@link UserAdmin} service.
+ * <p>
+ * In this context, the term &quot;user&quot; is not limited to just
+ * human beings.
+ * Instead, it refers to any entity that may have any number of
+ * credentials associated with it that it may use to authenticate itself.
+ * <p>
+ * In general, User objects are associated with a specific {@link UserAdmin}
+ * service (namely the one that created them), and cannot be used with other
+ * UserAdmin services.
+ * <p>
+ * A User may have credentials (and properties, inherited from {@link Role})
+ * associated with it. Specific {@link UserAdminPermission}s are required to
+ * read or change a User's credentials.
+ * <p>
+ * Credentials are Dictionary objects and have semantics that are similar
+ * to the properties in Role.
+ */
+
+public class User extends Role implements org.osgi.service.useradmin.User {
+
+ protected UserAdminHashtable credentials;
+ protected UserAdmin useradmin;
+
+ protected User(String name, UserAdmin useradmin) {
+ super(name, useradmin);
+ this.useradmin = useradmin;
+ credentials = new UserAdminHashtable(this, useradmin, UserAdminHashtable.CREDENTIALS);
+ }
+
+ /**
+ * Returns a Dictionary of the credentials of this User. Any changes
+ * to the returned Dictionary will change the credentials of this User.
+ * This will cause a UserAdminEvent of type
+ * {@link UserAdminEvent#ROLE_CHANGED} to be broadcast to any
+ * UserAdminListeners.
+ * <p>
+ * Only objects of type String may be used as credential keys, and only
+ * objects of type <code>String</code> or of type <code>byte[]</code>
+ * may be used as credential values. Any other types will cause an exception
+ * of type <code>IllegalArgumentException</code> to be raised.
+ * <p>
+ * In order to retrieve a credential from the returned Dictionary,
+ * a {@link UserAdminPermission} named after the credential name (or
+ * a prefix of it) with action <code>getCredential</code> is required.
+ * <p>
+ * In order to add or remove a credential from the returned Dictionary,
+ * a {@link UserAdminPermission} named after the credential name (or
+ * a prefix of it) with action <code>changeCredential</code> is required.
+ *
+ * @return Dictionary containing the credentials of this User.
+ */
+
+ public Dictionary getCredentials() {
+ useradmin.checkAlive();
+ return (credentials);
+ }
+
+ /**
+ * Checks to see if this User has a credential with the specified key
+ * set to the specified value.
+ * <p>
+ * If the specified credential value is not of type <tt>String</tt> or
+ * <tt>byte[]</tt>, it is ignored, that is, <tt>false</tt> is returned
+ * (as opposed to an <tt>IllegalArgumentException</tt> being raised).
+ *
+ * @param key The credential key.
+ * @param value The credential value.
+ *
+ * @return <code>true</code> if this user has the specified credential;
+ * <code>false</code> otherwise.
+ *
+ * @throws SecurityException If a security manager exists and the caller
+ * does not have the <tt>UserAdminPermission</tt> named after the credential
+ * key (or a prefix of it) with action <code>getCredential</code>.
+ */
+ public boolean hasCredential(String key, Object value) {
+ useradmin.checkAlive();
+ Object checkValue = credentials.get(key);
+ if (checkValue != null) {
+ if (value instanceof String) {
+ if (checkValue.equals(value)) {
+ return (true);
+ }
+ } else if (value instanceof byte[])//FIXME Is there a good way to do this compare???
+ {
+ if (!(checkValue instanceof byte[])) {
+ return (false);
+ }
+ //???do they need to be in order?
+ byte[] valueArray = (byte[]) value;
+ byte[] checkValueArray = (byte[]) checkValue;
+ int length = valueArray.length;
+ if (length != checkValueArray.length) {
+ return (false);
+ }
+ for (int i = 0; i < length; i++) {
+ if (valueArray[i] != checkValueArray[i]) {
+ return (false);
+ }
+ }
+ return (true);
+ }
+ }
+ return (false); //if checkValue is null
+ }
+
+ /**
+ * Returns the type of this role.
+ *
+ * @return The role's type.
+ */
+ public int getType() {
+ useradmin.checkAlive();
+ return Role.USER;
+ }
+
+ //A user always implies itself
+ protected boolean isImpliedBy(Role role, Vector checkLoop) {
+ if (checkLoop.contains(name)) {
+ //we have a circular dependency
+ return (false);
+ }
+ checkLoop.addElement(name);
+ return ((role.getName()).equals(name));
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdmin.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdmin.java
new file mode 100644
index 000000000..e0e079324
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdmin.java
@@ -0,0 +1,355 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.util.*;
+import org.osgi.framework.*;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.PreferencesService;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminPermission;
+
+/**
+ * This interface is used to manage a database of named roles, which can
+ * be used for authentication and authorization purposes.
+ * <p>
+ * This version of UserAdmin defines two types of roles: "User" and
+ * "Group". Each type of role is represented by an "int" constant and an
+ * interface. The range of positive integers is reserved for new types of
+ * roles that may be added in the future. When defining proprietary role
+ * types, negative constant values must be used.
+ * <p>
+ * Every role has a name and a type.
+ * <p>
+ * A {@link User} role can be configured with credentials (e.g., a password)
+ * and properties (e.g., a street address, phone number, etc.).
+ * <p>
+ * A {@link Group} role represents an aggregation of {@link User} and
+ * {@link Group} roles. In
+ * other words, the members of a Group role are roles themselves.
+ * <p>
+ * Every UserAdmin manages and maintains its own
+ * namespace of roles, in which each role has a unique name.
+ */
+
+public class UserAdmin implements org.osgi.service.useradmin.UserAdmin {
+
+ protected Vector users;
+ protected Vector roles;
+ protected BundleContext context;
+ protected UserAdminEventProducer eventProducer;
+ protected boolean alive;
+ protected UserAdminStore userAdminStore;
+ protected UserAdminPermission adminPermission;
+ protected ServiceReference reference;
+ protected LogTracker log;
+
+ protected UserAdmin(PreferencesService preferencesService, BundleContext context) throws Exception {
+ roles = new Vector();
+ users = new Vector();
+ this.context = context;
+
+ log = new LogTracker(context, System.out);
+ alive = true;
+ //This handles user admin persistence
+ try {
+ userAdminStore = new UserAdminStore(preferencesService, this, log);
+ userAdminStore.init();
+ } catch (Exception e) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Read_Exception, e);
+ throw e;
+ }
+ }
+
+ protected void setServiceReference(ServiceReference reference) {
+ if (this.reference == null) {
+ this.reference = reference;
+
+ eventProducer = new UserAdminEventProducer(reference, context, log);
+ }
+ }
+
+ /**
+ * Creates a role with the given name and of the given type.
+ *
+ * <p> If a role was created, a UserAdminEvent of type
+ * {@link UserAdminEvent#ROLE_CREATED} is broadcast to any
+ * UserAdminListener.
+ *
+ * @param name The name of the role to create.
+ * @param type The type of the role to create. Must be either
+ * {@link Role#USER} or {@link Role#GROUP}.
+ *
+ * @return The newly created role, or <code>null</code> if a role with
+ * the given name already exists.
+ *
+ * @throws IllegalArgumentException if <tt>type</tt> is invalid.
+ *
+ * @throws SecurityException If a security manager exists and the caller
+ * does not have the <tt>UserAdminPermission</tt> with name <tt>admin</tt>.
+ */
+ public org.osgi.service.useradmin.Role createRole(String name, int type) {
+ checkAlive();
+ checkAdminPermission();
+ if (name == null) {
+ throw (new IllegalArgumentException(UserAdminMsg.CREATE_NULL_ROLE_EXCEPTION));
+ }
+ if ((type != Role.GROUP) && (type != Role.USER)) {
+ throw (new IllegalArgumentException(UserAdminMsg.CREATE_INVALID_TYPE_ROLE_EXCEPTION));
+ }
+ //if the role already exists, return null
+ if (getRole(name) != null) {
+ return (null);
+ }
+
+ synchronized (this) {
+ return createRole(name, type, true);
+ }
+ }
+
+ protected org.osgi.service.useradmin.Role createRole(String name, int type, boolean store) {
+ Role newRole = null;
+ if (type == Role.ROLE) {
+ newRole = new Role(name, this);
+ } else if (type == Role.USER) {
+ newRole = new User(name, this);
+ } else if (type == Role.GROUP) {
+ newRole = new Group(name, this);
+ } else //unknown type
+ {
+ return (null);
+ }
+ if (store) {
+ try {
+ userAdminStore.addRole(newRole);
+ } catch (BackingStoreException ex) {
+ return (null);
+ }
+ if (eventProducer != null) {
+ eventProducer.generateEvent(UserAdminEvent.ROLE_CREATED, newRole);
+ }
+ }
+ if (type == Role.GROUP || type == Role.USER) {
+ users.addElement(newRole);
+ }
+ roles.addElement(newRole);
+ return (newRole);
+ }
+
+ /**
+ * Removes the role with the given name from this UserAdmin.
+ *
+ * <p> If the role was removed, a UserAdminEvent of type
+ * {@link UserAdminEvent#ROLE_REMOVED} is broadcast to any
+ * UserAdminListener.
+ *
+ * @param name The name of the role to remove.
+ *
+ * @return <code>true</code> If a role with the given name is present in this
+ * UserAdmin and could be removed, otherwise <code>false</code>.
+ *
+ * @throws SecurityException If a security manager exists and the caller
+ * does not have the <tt>UserAdminPermission</tt> with name <tt>admin</tt>.
+ */
+ public boolean removeRole(String name) {
+ checkAlive();
+ checkAdminPermission();
+ if (name.equals(Role.anyoneString)) {
+ //silently ignore
+ return (true);
+ }
+ synchronized (this) {
+ Role role = (org.eclipse.equinox.useradmin.Role) getRole(name);
+ if (role != null) {
+ try {
+ userAdminStore.removeRole(role);
+ } catch (BackingStoreException ex) {
+ return (false);
+ }
+ roles.removeElement(role);
+ users.removeElement(role);
+ role.destroy();
+ eventProducer.generateEvent(UserAdminEvent.ROLE_REMOVED, role);
+ role = null;
+ return (true);
+ }
+ return (false);
+ }
+ }
+
+ /**
+ * Gets the role with the given name from this UserAdmin.
+ *
+ * @param name The name of the role to get.
+ *
+ * @return The requested role, or <code>null</code> if this UserAdmin does
+ * not have a role with the given name.
+ */
+ public org.osgi.service.useradmin.Role getRole(String name) {
+ checkAlive();
+ if (name == null) {
+ return (null);
+ }
+ synchronized (this) {
+ Enumeration e = roles.elements();
+ while (e.hasMoreElements()) {
+ Role role = (Role) e.nextElement();
+ if (role.getName().equals(name)) {
+ return (role);
+ }
+ }
+ return (null);
+ }
+ }
+
+ /**
+ * Gets the roles managed by this UserAdmin that have properties matching
+ * the specified LDAP filter criteria. See
+ * <code>org.osgi.framework.Filter</code> or IETF RFC 2254 for a
+ * description of the filter syntax. If a <code>null</code> filter is
+ * specified, all roles managed by this UserAdmin are returned.
+ *
+ * @param filter The filter criteria to match.
+ *
+ * @return The roles managed by this UserAdmin whose properties
+ * match the specified filter criteria, or all roles if a
+ * <code>null</code> filter is specified.
+ *
+ */
+ public org.osgi.service.useradmin.Role[] getRoles(String filterString) throws InvalidSyntaxException {
+ checkAlive();
+ Vector returnedRoles;
+ synchronized (this) {
+ if (filterString == null) {
+ returnedRoles = roles;
+ } else {
+ Filter filter = context.createFilter(filterString); //We do this first so an
+ //InvalidSyntaxException will be
+ //thrown even if there are no roles
+ //present.
+ returnedRoles = new Vector();
+ for (int i = 0; i < roles.size(); i++) {
+ Role role = (Role) roles.elementAt(i);
+ if (filter.match(role.getProperties())) {
+ returnedRoles.addElement(role);
+ }
+ }
+ }
+ int size = returnedRoles.size();
+ if (size == 0) {
+ return (null);
+ }
+ Role[] roleArray = new Role[size];
+ returnedRoles.copyInto(roleArray);
+ return (roleArray);
+ }
+ }
+
+ /**
+ * Gets the user with the given property key-value pair from the UserAdmin
+ * database. This is a convenience method for retrieving a user based on
+ * a property for which every user is supposed to have a unique value
+ * (within the scope of this UserAdmin), such as a user's
+ * X.500 distinguished name.
+ *
+ * @param key The property key to look for.
+ * @param value The property value to compare with.
+ *
+ * @return A matching user, if <em>exactly</em> one is found. If zero or
+ * more than one matching users are found, <code>null</code> is returned.
+ */
+ public org.osgi.service.useradmin.User getUser(String key, String value) {
+ checkAlive();
+ if (key == null) {
+ return (null);
+ }
+ User user;
+ User foundUser = null;
+ Dictionary props;
+ String keyValue;
+ synchronized (this) {
+ Enumeration e = users.elements();
+ while (e.hasMoreElements()) {
+ user = (User) e.nextElement();
+ props = user.getProperties();
+ keyValue = (String) props.get(key);
+ if (keyValue != null && keyValue.equals(value)) {
+ if (foundUser != null) {
+ return (null); //we found more than one match
+ }
+ foundUser = user;
+ }
+ }
+ return (foundUser);
+ }
+ }
+
+ /**
+ * Creates an Authorization object that encapsulates the specified user
+ * and the roles it possesses. The <code>null</code> user is interpreted
+ * as the anonymous user.
+ *
+ * @param user The user to create an Authorization object for, or
+ * <code>null</code> for the anonymous user.
+ *
+ * @return the Authorization object for the specified user.
+ */
+ public org.osgi.service.useradmin.Authorization getAuthorization(org.osgi.service.useradmin.User user) {
+ checkAlive();
+ return (new Authorization((User) user, this));
+ }
+
+ protected synchronized void destroy() {
+ alive = false;
+ eventProducer.close();
+ userAdminStore.destroy();
+
+ log.close();
+ }
+
+ public void checkAdminPermission() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ if (adminPermission == null) {
+ adminPermission = new UserAdminPermission(UserAdminPermission.ADMIN, null);
+ }
+ sm.checkPermission(adminPermission);
+ }
+ }
+
+ public void checkGetCredentialPermission(String credential) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new org.osgi.service.useradmin.UserAdminPermission(credential, org.osgi.service.useradmin.UserAdminPermission.GET_CREDENTIAL));
+ }
+ }
+
+ public void checkChangeCredentialPermission(String credential) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new org.osgi.service.useradmin.UserAdminPermission(credential, org.osgi.service.useradmin.UserAdminPermission.CHANGE_CREDENTIAL));
+ }
+ }
+
+ public void checkChangePropertyPermission(String property) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new org.osgi.service.useradmin.UserAdminPermission(property, org.osgi.service.useradmin.UserAdminPermission.CHANGE_PROPERTY));
+ }
+ }
+
+ public void checkAlive() {
+ if (!alive) {
+ throw (new IllegalStateException(UserAdminMsg.USERADMIN_UNREGISTERED_EXCEPTION));
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminEventProducer.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminEventProducer.java
new file mode 100644
index 000000000..aa3af0a13
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminEventProducer.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import org.eclipse.osgi.framework.eventmgr.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.UserAdminEvent;
+import org.osgi.service.useradmin.UserAdminListener;
+import org.osgi.util.tracker.ServiceTracker;
+
+/*
+ * UserAdminEventProducer is responsible for sending out UserAdminEvents
+ * to all UserAdminListeners.
+ */
+
+public class UserAdminEventProducer extends ServiceTracker implements EventDispatcher {
+
+ protected ServiceReference userAdmin;
+ static protected final String userAdminListenerClass = "org.osgi.service.useradmin.UserAdminListener"; //$NON-NLS-1$
+ protected LogService log;
+ /** List of UserAdminListeners */
+ protected EventListeners listeners;
+ /** EventManager for event delivery. */
+ protected EventManager eventManager;
+
+ protected UserAdminEventProducer(ServiceReference userAdmin, BundleContext context, LogService log) {
+ super(context, userAdminListenerClass, null);
+ this.userAdmin = userAdmin;
+ this.log = log;
+ eventManager = new EventManager();
+ listeners = new EventListeners();
+
+ open();
+ }
+
+ public void close() {
+ super.close();
+ listeners.removeAllListeners();
+ eventManager.close();
+ userAdmin = null;
+ }
+
+ protected void generateEvent(int type, Role role) {
+ if (userAdmin != null) {
+ UserAdminEvent event = new UserAdminEvent(userAdmin, type, role);
+
+ /* queue to hold set of listeners */
+ ListenerQueue queue = new ListenerQueue(eventManager);
+
+ /* add set of UserAdminListeners to queue */
+ queue.queueListeners(listeners, this);
+
+ /* dispatch event to set of listeners */
+ queue.dispatchEventAsynchronous(0, event);
+ }
+ }
+
+ /**
+ * A service is being added to the <tt>ServiceTracker</tt> object.
+ *
+ * <p>This method is called before a service which matched
+ * the search parameters of the <tt>ServiceTracker</tt> object is
+ * added to it. This method should return the
+ * service object to be tracked for this <tt>ServiceReference</tt> object.
+ * The returned service object is stored in the <tt>ServiceTracker</tt> object
+ * and is available from the <tt>getService</tt> and <tt>getServices</tt>
+ * methods.
+ *
+ * @param reference Reference to service being added to the <tt>ServiceTracker</tt> object.
+ * @return The service object to be tracked for the
+ * <tt>ServiceReference</tt> object or <tt>null</tt> if the <tt>ServiceReference</tt> object should not
+ * be tracked.
+ */
+ public Object addingService(ServiceReference reference) {
+ Object service = super.addingService(reference);
+
+ listeners.addListener(service, service);
+
+ return service;
+ }
+
+ /**
+ * A service tracked by the <tt>ServiceTracker</tt> object has been removed.
+ *
+ * <p>This method is called after a service is no longer being tracked
+ * by the <tt>ServiceTracker</tt> object.
+ *
+ * @param reference Reference to service that has been removed.
+ * @param service The service object for the removed service.
+ */
+ public void removedService(ServiceReference reference, Object service) {
+ listeners.removeListener(service);
+
+ super.removedService(reference, service);
+ }
+
+ /**
+ * This method is the call back that is called once for each listener.
+ * This method must cast the EventListener object to the appropriate listener
+ * class for the event type and call the appropriate listener method.
+ *
+ * @param listener This listener must be cast to the appropriate listener
+ * class for the events created by this source and the appropriate listener method
+ * must then be called.
+ * @param listenerObject This is the optional object that was passed to
+ * ListenerList.addListener when the listener was added to the ListenerList.
+ * @param eventAction This value was passed to the EventQueue object via one of its
+ * dispatchEvent* method calls. It can provide information (such
+ * as which listener method to call) so that this method
+ * can complete the delivery of the event to the listener.
+ * @param eventObject This object was passed to the EventQueue object via one of its
+ * dispatchEvent* method calls. This object was created by the event source and
+ * is passed to this method. It should contain all the necessary information (such
+ * as what event object to pass) so that this method
+ * can complete the delivery of the event to the listener.
+ */
+ public void dispatchEvent(Object listener, Object listenerObject, int eventAction, Object eventObject) {
+ ServiceReference userAdmin = this.userAdmin;
+
+ if (userAdmin == null) {
+ return;
+ }
+
+ UserAdminListener ual = (UserAdminListener) listener;
+ try {
+ ual.roleChanged((UserAdminEvent) eventObject);
+ } catch (Throwable t) {
+ log.log(userAdmin, log.LOG_WARNING, UserAdminMsg.Event_Delivery_Exception, t);
+ }
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminHashtable.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminHashtable.java
new file mode 100644
index 000000000..c1b124f08
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminHashtable.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.useradmin.UserAdminEvent;
+
+/* The UserAdminHashtable is a Hashtable that generates UserAdminEvents when there
+ * is a change to the Hashtable. This is used specifically to store Role properties
+ * and User credentials.
+ */
+
+public class UserAdminHashtable extends Hashtable {
+
+ protected Role role;
+ protected int propertyType;
+ protected UserAdmin userAdmin;
+ protected UserAdminStore userAdminStore;
+
+ //TODO - split this into two classes so we don't have to do this
+ protected static final int CREDENTIALS = 0;
+ protected static final int PROPERTIES = 1;
+
+ protected UserAdminHashtable(Role role, UserAdmin userAdmin, int propertyType) {
+ this.role = role;
+ this.propertyType = propertyType;
+ this.userAdmin = userAdmin;
+ this.userAdminStore = userAdmin.userAdminStore;
+ }
+
+ /*
+ * We want to generate an event every time we put something into the hashtable, except
+ * upon initialization where role data is being read from persistent store.
+ */
+ protected synchronized Object put(String key, Object value, boolean generateEvent) {
+
+ if (generateEvent) {
+ if (propertyType == UserAdminHashtable.PROPERTIES) {
+ try {
+ userAdminStore.addProperty(role, key, value);
+ } catch (BackingStoreException ex) {
+ return (null);
+ }
+ userAdmin.eventProducer.generateEvent(UserAdminEvent.ROLE_CHANGED, role);
+ } else if (propertyType == UserAdminHashtable.CREDENTIALS) {
+ try {
+ userAdminStore.addCredential(role, key, value);
+ } catch (BackingStoreException ex) {
+ return (null);
+ }
+ userAdmin.eventProducer.generateEvent(UserAdminEvent.ROLE_CHANGED, role);
+ }
+ }
+ Object retVal = super.put(key, value);
+ return retVal;
+ }
+
+ public Object put(Object key, Object value) {
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException(UserAdminMsg.INVALID_KEY_EXCEPTION);
+ }
+
+ if (!((value instanceof String) || (value instanceof byte[]))) {
+ throw new IllegalArgumentException(UserAdminMsg.INVALID_VALUE_EXCEPTION);
+ }
+
+ String name = (String) key;
+
+ switch (propertyType) {
+ case PROPERTIES :
+ userAdmin.checkChangePropertyPermission(name);
+ break;
+ case CREDENTIALS :
+ userAdmin.checkChangeCredentialPermission(name);
+ break;
+ }
+
+ return put(name, value, true);
+ }
+
+ public synchronized Object remove(Object key) {
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException(UserAdminMsg.INVALID_KEY_EXCEPTION);
+ }
+
+ String name = (String) key;
+
+ switch (propertyType) {
+ case PROPERTIES :
+ userAdmin.checkChangePropertyPermission(name);
+ try {
+ userAdminStore.removeProperty(role, name);
+ } catch (BackingStoreException ex) {
+ return (null);
+ }
+ userAdmin.eventProducer.generateEvent(UserAdminEvent.ROLE_CHANGED, role);
+ break;
+ case CREDENTIALS :
+ userAdmin.checkChangeCredentialPermission(name);
+ try {
+ userAdminStore.removeCredential(role, name);
+ } catch (BackingStoreException ex) {
+ return (null);
+ }
+ userAdmin.eventProducer.generateEvent(UserAdminEvent.ROLE_CHANGED, role);
+ break;
+ }
+
+ return super.remove(name);
+ }
+
+ public synchronized void clear() {
+ Enumeration enum = keys();
+
+ while (enum.hasMoreElements()) {
+ String name = (String) enum.nextElement();
+
+ switch (propertyType) {
+ case PROPERTIES :
+ userAdmin.checkChangePropertyPermission(name);
+ break;
+ case CREDENTIALS :
+ userAdmin.checkChangeCredentialPermission(name);
+ break;
+ }
+ }
+
+ switch (propertyType) {
+ case PROPERTIES :
+ try {
+ userAdminStore.clearProperties(role);
+ } catch (BackingStoreException ex) {
+ return;
+ }
+ userAdmin.eventProducer.generateEvent(UserAdminEvent.ROLE_CHANGED, role);
+ break;
+ case CREDENTIALS :
+ try {
+ userAdminStore.clearCredentials(role);
+ } catch (BackingStoreException ex) {
+ return;
+ }
+ userAdmin.eventProducer.generateEvent(UserAdminEvent.ROLE_CHANGED, role);
+ break;
+ }
+
+ super.clear();
+ }
+
+ public Object get(Object key) {
+ if (!(key instanceof String)) {
+ throw new IllegalArgumentException(UserAdminMsg.INVALID_KEY_EXCEPTION);
+ }
+
+ String name = (String) key;
+
+ if (propertyType == CREDENTIALS) {
+ userAdmin.checkGetCredentialPermission(name);
+ }
+
+ return super.get(name);
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminMsg.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminMsg.java
new file mode 100644
index 000000000..be4bf7618
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminMsg.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import org.eclipse.osgi.util.NLS;
+
+public class UserAdminMsg extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.equinox.useradmin.ExternalMessages"; //$NON-NLS-1$
+
+ public static String adding_Credential_to__15;
+ public static String adding_member__18;
+ public static String adding_required_member__21;
+ public static String removing_member__24;
+ public static String Unable_to_load_role__27;
+ public static String Backing_Store_Read_Exception;
+ public static String Backing_Store_Write_Exception;
+ public static String Event_Delivery_Exception;
+ public static String CREATE_NULL_ROLE_EXCEPTION;
+ public static String CREATE_INVALID_TYPE_ROLE_EXCEPTION;
+ public static String INVALID_KEY_EXCEPTION;
+ public static String INVALID_VALUE_EXCEPTION;
+ public static String USERADMIN_UNREGISTERED_EXCEPTION;
+ public static String Service_Vendor;
+ public static String OSGi_User_Admin_service_IBM_Implementation_3;
+
+ static {
+ // initialize resource bundles
+ NLS.initializeMessages(BUNDLE_NAME, UserAdminMsg.class);
+ }
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminStore.java b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminStore.java
new file mode 100644
index 000000000..557aeca45
--- /dev/null
+++ b/bundles/org.eclipse.equinox.useradmin/src/org/eclipse/equinox/useradmin/UserAdminStore.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2005 IBM Corporation.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.useradmin;
+
+import java.security.*;
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+import org.osgi.service.prefs.*;
+
+/*
+ * UserAdminStore is responsible for managing the persistence data of the useradmin
+ * service. It uses the PersistenceNode service as its underlying storage.
+ */
+
+public class UserAdminStore {
+
+ static protected final String propertiesNode = "properties"; //$NON-NLS-1$
+ static protected final String credentialsNode = "credentials"; //$NON-NLS-1$
+ static protected final String membersNode = "members"; //$NON-NLS-1$
+ static protected final String basicString = "basic"; //$NON-NLS-1$
+ static protected final String requiredString = "required"; //$NON-NLS-1$
+ static protected final String typeString = "type"; //$NON-NLS-1$
+ static protected final String persistenceUserName = "UserAdmin"; //$NON-NLS-1$
+
+ protected ServiceReference prefsRef;
+ protected ServiceRegistration userAdminListenerReg;
+ protected UserAdmin useradmin;
+ protected LogService log;
+ protected Preferences rootNode;
+ protected PreferencesService preferencesService;
+
+ protected UserAdminStore(PreferencesService preferencesService, UserAdmin useradmin, LogService log) {
+ this.preferencesService = preferencesService;
+ this.useradmin = useradmin;
+ this.log = log;
+ }
+
+ protected void init() throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+
+ public Object run() throws BackingStoreException {
+ rootNode = preferencesService.getUserPreferences(persistenceUserName);
+ loadRoles();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void addRole(final org.osgi.service.useradmin.Role role) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences node = rootNode.node(role.getName());
+ node.putInt(typeString, role.getType());
+ node.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void removeRole(final org.osgi.service.useradmin.Role role) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences node = rootNode.node(role.getName());
+ node.removeNode();
+ rootNode.node("").flush(); //$NON-NLS-1$
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void clearProperties(final org.osgi.service.useradmin.Role role) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences propertyNode = rootNode.node(role.getName() + "/" + propertiesNode); //$NON-NLS-1$
+ propertyNode.clear();
+ propertyNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void addProperty(final org.osgi.service.useradmin.Role role, final String key, final Object value) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences propertyNode = rootNode.node(role.getName() + "/" + propertiesNode); //$NON-NLS-1$
+ if (value instanceof String) {
+ propertyNode.put(key, (String) value);
+ } else //must be a byte array, then
+ {
+ propertyNode.putByteArray(key, (byte[]) value);
+ }
+ propertyNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void removeProperty(final org.osgi.service.useradmin.Role role, final String key) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences propertyNode = rootNode.node(role.getName() + "/" + propertiesNode); //$NON-NLS-1$
+ propertyNode.remove(key);
+ propertyNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void clearCredentials(final org.osgi.service.useradmin.Role role) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences credentialNode = rootNode.node(role.getName() + "/" + credentialsNode); //$NON-NLS-1$
+ credentialNode.clear();
+ credentialNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void addCredential(final org.osgi.service.useradmin.Role role, final String key, final Object value) throws BackingStoreException {
+
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences credentialNode = rootNode.node(role.getName() + "/" + credentialsNode); //$NON-NLS-1$
+ if (value instanceof String) {
+ credentialNode.put(key, (String) value);
+ } else //assume it is a byte array
+ {
+ credentialNode.putByteArray(key, (byte[]) value);
+ }
+ credentialNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, NLS.bind(UserAdminMsg.Backing_Store_Write_Exception, new Object[] {NLS.bind(UserAdminMsg.adding_Credential_to__15, role.getName())}), ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+
+ }
+
+ protected void removeCredential(final org.osgi.service.useradmin.Role role, final String key) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences credentialNode = rootNode.node(role.getName() + "/" + credentialsNode); //$NON-NLS-1$
+ credentialNode.remove(key);
+ credentialNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void addMember(final Group group, final Role role) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences memberNode = rootNode.node(group.getName() + "/" + membersNode); //$NON-NLS-1$
+ memberNode.put(role.getName(), basicString);
+ memberNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, NLS.bind(UserAdminMsg.Backing_Store_Write_Exception, new Object[] {NLS.bind(UserAdminMsg.adding_member__18, role.getName(), group.getName())}), ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void addRequiredMember(final Group group, final Role role) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences memberNode = rootNode.node(group.getName() + "/" + membersNode); //$NON-NLS-1$
+ memberNode.put(role.getName(), requiredString);
+ memberNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, NLS.bind(UserAdminMsg.Backing_Store_Write_Exception, new Object[] {NLS.bind(UserAdminMsg.adding_required_member__21, role.getName(), group.getName())}), ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void removeMember(final Group group, final Role role) throws BackingStoreException {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws BackingStoreException {
+ Preferences memberNode = rootNode.node(group.getName() + "/" + membersNode); //$NON-NLS-1$
+ memberNode.remove(role.getName());
+ memberNode.flush();
+ return (null);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ log.log(log.LOG_ERROR, NLS.bind(UserAdminMsg.Backing_Store_Write_Exception, new Object[] {NLS.bind(UserAdminMsg.removing_member__24, role.getName(), group.getName())}), ex);
+ throw ((BackingStoreException) ex.getException());
+ }
+ }
+
+ protected void loadRoles() throws BackingStoreException {
+ synchronized (this) {
+ createAnonRole();
+
+ String[] children = rootNode.node("").childrenNames(); //$NON-NLS-1$
+
+ for (int i = 0; i < children.length; i++) {
+ if (useradmin.getRole(children[i]) == null) //check to see if it is already loaded
+ { //(we may have had to load some roles out of
+ loadRole(rootNode.node(children[i]), null); // order due to dependencies)
+ //modified to solve defect 95982
+ }
+ }
+ }
+ }
+
+ /* modified to solve defect 95982 */
+ protected void loadRole(Preferences node, Role role) throws BackingStoreException {
+ int type = node.getInt(typeString, Integer.MIN_VALUE);
+
+ if (type == Integer.MIN_VALUE) {
+ String errorString = NLS.bind(UserAdminMsg.Backing_Store_Read_Exception, new Object[] {NLS.bind(UserAdminMsg.Unable_to_load_role__27, node.name())});
+ BackingStoreException ex = new BackingStoreException(errorString);
+ log.log(log.LOG_ERROR, errorString, ex);
+ throw (ex);
+ }
+ if (role == null) {
+ role = (Role) useradmin.createRole(node.name(), type, false);
+ }
+ Preferences propsNode = node.node(propertiesNode);
+ String[] keys = propsNode.keys();
+ UserAdminHashtable properties = (UserAdminHashtable) role.getProperties();
+ String value;
+
+ //load properties
+ for (int i = 0; i < keys.length; i++) {
+ value = propsNode.get(keys[i], null);
+ properties.put(keys[i], value, false);
+ }
+
+ //load credentials
+ if (type == Role.USER || type == Role.GROUP) {
+ Object credValue;
+ Preferences credNode = node.node(credentialsNode);
+ keys = credNode.keys();
+ UserAdminHashtable credentials = (UserAdminHashtable) ((User) role).getCredentials();
+ for (int i = 0; i < keys.length; i++) {
+ credValue = credNode.get(keys[i], null);
+ credentials.put(keys[i], credValue, false);
+ }
+ }
+
+ //load group members
+ if (type == Role.GROUP) {
+ Preferences memberNode = node.node(membersNode);
+ keys = memberNode.keys();
+ for (int i = 0; i < keys.length; i++) {
+ value = memberNode.get(keys[i], null);
+ Role member = (Role) useradmin.getRole(keys[i]);
+ if (member == null) //then we have not loaded this one yet, so load it
+ {
+ loadRole(rootNode.node(keys[i]), null); // modified to solve defect 95982
+ member = (Role) useradmin.getRole(keys[i]);
+ }
+ if (value.equals(requiredString)) {
+ ((Group) role).addRequiredMember(member, false);
+ } else {
+ ((Group) role).addMember(member, false);
+ }
+ }
+ }
+ }
+
+ protected void destroy() {
+ try {
+ rootNode.flush();
+ rootNode = null;
+ preferencesService = null;
+ } catch (BackingStoreException ex) {
+ log.log(log.LOG_ERROR, UserAdminMsg.Backing_Store_Write_Exception, ex);
+ }
+ }
+
+ private void createAnonRole() throws BackingStoreException {
+ Role role = null;
+ if (!rootNode.nodeExists(Role.anyoneString)) {
+ //If the user.anyone role is not present, create it
+ role = (Role) useradmin.createRole(Role.anyoneString, Role.ROLE, true);
+ }
+ /* modified to solve defect 95982 */
+ if (role != null)
+ loadRole(rootNode.node(Role.anyoneString), role);
+ else
+ loadRole(rootNode.node(Role.anyoneString), null);
+ }
+
+}

Back to the top