blob: e8493d18077821e09a05fc25c5bbfc2cb5a48f4c [file] [log] [blame]
/*******************************************************************************
* 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.Enumeration;
import java.util.Vector;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
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(LogService.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 != org.osgi.service.useradmin.Role.GROUP) && (type != org.osgi.service.useradmin.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 == org.osgi.service.useradmin.Role.ROLE) {
newRole = new Role(name, this);
} else if (type == org.osgi.service.useradmin.Role.USER) {
newRole = new User(name, this);
} else if (type == org.osgi.service.useradmin.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 == org.osgi.service.useradmin.Role.GROUP || type == org.osgi.service.useradmin.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));
}
}
}