1 /*******************************************************************************
2  * Copyright (c) 2001, 2008 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.equinox.internal.useradmin;
15 
16 import java.util.*;
17 import org.osgi.framework.*;
18 import org.osgi.service.log.LogService;
19 import org.osgi.service.prefs.BackingStoreException;
20 import org.osgi.service.prefs.PreferencesService;
21 import org.osgi.service.useradmin.UserAdminEvent;
22 import org.osgi.service.useradmin.UserAdminPermission;
23 
24 /**
25  * This interface is used to manage a database of named roles, which can
26  * be used for authentication and authorization purposes.
27  * <p>
28  * This version of UserAdmin defines two types of roles: "User" and
29  * "Group". Each type of role is represented by an "int" constant and an
30  * interface. The range of positive integers is reserved for new types of
31  * roles that may be added in the future. When defining proprietary role
32  * types, negative constant values must be used.
33  * <p>
34  * Every role has a name and a type.
35  * <p>
36  * A {@link User} role can be configured with credentials (e.g., a password)
37  * and properties (e.g., a street address, phone number, etc.).
38  * <p>
39  * A {@link Group} role represents an aggregation of {@link User} and
40  * {@link Group} roles. In
41  * other words, the members of a Group role are roles themselves.
42  * <p>
43  * Every UserAdmin manages and maintains its own
44  * namespace of roles, in which each role has a unique name.
45  */
46 
47 public class UserAdmin implements org.osgi.service.useradmin.UserAdmin {
48 
49 	protected Vector users;
50 	protected Vector roles;
51 	protected BundleContext context;
52 	protected UserAdminEventProducer eventProducer;
53 	protected boolean alive;
54 	protected UserAdminStore userAdminStore;
55 	protected UserAdminPermission adminPermission;
56 	protected ServiceReference reference;
57 	protected LogTracker log;
58 
UserAdmin(PreferencesService preferencesService, BundleContext context)59 	protected UserAdmin(PreferencesService preferencesService, BundleContext context) throws Exception {
60 		roles = new Vector();
61 		users = new Vector();
62 		this.context = context;
63 
64 		log = new LogTracker(context, System.out);
65 		alive = true;
66 		//This handles user admin persistence
67 		try {
68 			userAdminStore = new UserAdminStore(preferencesService, this, log);
69 			userAdminStore.init();
70 		} catch (Exception e) {
71 			log.log(LogService.LOG_ERROR, UserAdminMsg.Backing_Store_Read_Exception, e);
72 			throw e;
73 		}
74 	}
75 
setServiceReference(ServiceReference reference)76 	protected void setServiceReference(ServiceReference reference) {
77 		if (this.reference == null) {
78 			this.reference = reference;
79 
80 			eventProducer = new UserAdminEventProducer(reference, context, log);
81 		}
82 	}
83 
84 	/**
85 	 * Creates a role with the given name and of the given type.
86 	 *
87 	 * <p> If a role was created, a UserAdminEvent of type
88 	 * {@link UserAdminEvent#ROLE_CREATED} is broadcast to any
89 	 * UserAdminListener.
90 	 *
91 	 * @param name The name of the role to create.
92 	 * @param type The type of the role to create. Must be either
93 	 * {@link Role#USER} or {@link Role#GROUP}.
94 	 *
95 	 * @return The newly created role, or <code>null</code> if a role with
96 	 * the given name already exists.
97 	 *
98 	 * @throws IllegalArgumentException if <tt>type</tt> is invalid.
99 	 *
100 	 * @throws SecurityException If a security manager exists and the caller
101 	 * does not have the <tt>UserAdminPermission</tt> with name <tt>admin</tt>.
102 	 */
createRole(String name, int type)103 	public org.osgi.service.useradmin.Role createRole(String name, int type) {
104 		checkAlive();
105 		checkAdminPermission();
106 		if (name == null) {
107 			throw (new IllegalArgumentException(UserAdminMsg.CREATE_NULL_ROLE_EXCEPTION));
108 		}
109 		if ((type != org.osgi.service.useradmin.Role.GROUP) && (type != org.osgi.service.useradmin.Role.USER)) {
110 			throw (new IllegalArgumentException(UserAdminMsg.CREATE_INVALID_TYPE_ROLE_EXCEPTION));
111 		}
112 		//if the role already exists, return null
113 		if (getRole(name) != null) {
114 			return (null);
115 		}
116 
117 		synchronized (this) {
118 			return createRole(name, type, true);
119 		}
120 	}
121 
createRole(String name, int type, boolean store)122 	protected org.osgi.service.useradmin.Role createRole(String name, int type, boolean store) {
123 		Role newRole = null;
124 		if (type == org.osgi.service.useradmin.Role.ROLE) {
125 			newRole = new Role(name, this);
126 		} else if (type == org.osgi.service.useradmin.Role.USER) {
127 			newRole = new User(name, this);
128 		} else if (type == org.osgi.service.useradmin.Role.GROUP) {
129 			newRole = new Group(name, this);
130 		} else //unknown type
131 		{
132 			return (null);
133 		}
134 		if (store) {
135 			try {
136 				userAdminStore.addRole(newRole);
137 			} catch (BackingStoreException ex) {
138 				return (null);
139 			}
140 			if (eventProducer != null) {
141 				eventProducer.generateEvent(UserAdminEvent.ROLE_CREATED, newRole);
142 			}
143 		}
144 		if (type == org.osgi.service.useradmin.Role.GROUP || type == org.osgi.service.useradmin.Role.USER) {
145 			users.addElement(newRole);
146 		}
147 		roles.addElement(newRole);
148 		return (newRole);
149 	}
150 
151 	/**
152 	 * Removes the role with the given name from this UserAdmin.
153 	 *
154 	 * <p> If the role was removed, a UserAdminEvent of type
155 	 * {@link UserAdminEvent#ROLE_REMOVED} is broadcast to any
156 	 * UserAdminListener.
157 	 *
158 	 * @param name The name of the role to remove.
159 	 *
160 	 * @return <code>true</code> If a role with the given name is present in this
161 	 * UserAdmin and could be removed, otherwise <code>false</code>.
162 	 *
163 	 * @throws SecurityException If a security manager exists and the caller
164 	 * does not have the <tt>UserAdminPermission</tt> with name <tt>admin</tt>.
165 	 */
removeRole(String name)166 	public boolean removeRole(String name) {
167 		checkAlive();
168 		checkAdminPermission();
169 		if (name.equals(Role.anyoneString)) {
170 			//silently ignore
171 			return (true);
172 		}
173 		synchronized (this) {
174 			Role role = (org.eclipse.equinox.internal.useradmin.Role) getRole(name);
175 			if (role != null) {
176 				try {
177 					userAdminStore.removeRole(role);
178 				} catch (BackingStoreException ex) {
179 					return (false);
180 				}
181 				roles.removeElement(role);
182 				users.removeElement(role);
183 				role.destroy();
184 				eventProducer.generateEvent(UserAdminEvent.ROLE_REMOVED, role);
185 				role = null;
186 				return (true);
187 			}
188 			return (false);
189 		}
190 	}
191 
192 	/**
193 	 * Gets the role with the given name from this UserAdmin.
194 	 *
195 	 * @param name The name of the role to get.
196 	 *
197 	 * @return The requested role, or <code>null</code> if this UserAdmin does
198 	 * not have a role with the given name.
199 	 */
getRole(String name)200 	public org.osgi.service.useradmin.Role getRole(String name) {
201 		checkAlive();
202 		if (name == null) {
203 			return (null);
204 		}
205 		synchronized (this) {
206 			Enumeration e = roles.elements();
207 			while (e.hasMoreElements()) {
208 				Role role = (Role) e.nextElement();
209 				if (role.getName().equals(name)) {
210 					return (role);
211 				}
212 			}
213 			return (null);
214 		}
215 	}
216 
217 	/**
218 	 * Gets the roles managed by this UserAdmin that have properties matching
219 	 * the specified LDAP filter criteria. See
220 	 * <code>org.osgi.framework.Filter</code> or IETF RFC 2254 for a
221 	 * description of the filter syntax. If a <code>null</code> filter is
222 	 * specified, all roles managed by this UserAdmin are returned.
223 	 *
224 	 * @param filterString The filter criteria to match.
225 	 *
226 	 * @return The roles managed by this UserAdmin whose properties
227 	 * match the specified filter criteria, or all roles if a
228 	 * <code>null</code> filter is specified.
229 	 *
230 	 */
getRoles(String filterString)231 	public org.osgi.service.useradmin.Role[] getRoles(String filterString) throws InvalidSyntaxException {
232 		checkAlive();
233 		Vector returnedRoles;
234 		synchronized (this) {
235 			if (filterString == null) {
236 				returnedRoles = roles;
237 			} else {
238 				Filter filter = context.createFilter(filterString); //We do this first so an
239 				//InvalidSyntaxException will be
240 				//thrown even if there are no roles
241 				//present.
242 				returnedRoles = new Vector();
243 				for (int i = 0; i < roles.size(); i++) {
244 					Role role = (Role) roles.elementAt(i);
245 					if (filter.match(role.getProperties())) {
246 						returnedRoles.addElement(role);
247 					}
248 				}
249 			}
250 			int size = returnedRoles.size();
251 			if (size == 0) {
252 				return (null);
253 			}
254 			Role[] roleArray = new Role[size];
255 			returnedRoles.copyInto(roleArray);
256 			return (roleArray);
257 		}
258 	}
259 
260 	/**
261 	 * Gets the user with the given property key-value pair from the UserAdmin
262 	 * database. This is a convenience method for retrieving a user based on
263 	 * a property for which every user is supposed to have a unique value
264 	 * (within the scope of this UserAdmin), such as a user's
265 	 * X.500 distinguished name.
266 	 *
267 	 * @param key The property key to look for.
268 	 * @param value The property value to compare with.
269 	 *
270 	 * @return A matching user, if <em>exactly</em> one is found. If zero or
271 	 * more than one matching users are found, <code>null</code> is returned.
272 	 */
getUser(String key, String value)273 	public org.osgi.service.useradmin.User getUser(String key, String value) {
274 		checkAlive();
275 		if (key == null) {
276 			return (null);
277 		}
278 		User user;
279 		User foundUser = null;
280 		Dictionary props;
281 		String keyValue;
282 		synchronized (this) {
283 			Enumeration e = users.elements();
284 			while (e.hasMoreElements()) {
285 				user = (User) e.nextElement();
286 				props = user.getProperties();
287 				keyValue = (String) props.get(key);
288 				if (keyValue != null && keyValue.equals(value)) {
289 					if (foundUser != null) {
290 						return (null); //we found more than one match
291 					}
292 					foundUser = user;
293 				}
294 			}
295 			return (foundUser);
296 		}
297 	}
298 
299 	/**
300 	 * Creates an Authorization object that encapsulates the specified user
301 	 * and the roles it possesses. The <code>null</code> user is interpreted
302 	 * as the anonymous user.
303 	 *
304 	 * @param user The user to create an Authorization object for, or
305 	 * <code>null</code> for the anonymous user.
306 	 *
307 	 * @return the Authorization object for the specified user.
308 	 */
getAuthorization(org.osgi.service.useradmin.User user)309 	public org.osgi.service.useradmin.Authorization getAuthorization(org.osgi.service.useradmin.User user) {
310 		checkAlive();
311 		return (new Authorization((User) user, this));
312 	}
313 
destroy()314 	protected synchronized void destroy() {
315 		alive = false;
316 		eventProducer.close();
317 		userAdminStore.destroy();
318 
319 		log.close();
320 	}
321 
checkAdminPermission()322 	public void checkAdminPermission() {
323 		SecurityManager sm = System.getSecurityManager();
324 		if (sm != null) {
325 			if (adminPermission == null) {
326 				adminPermission = new UserAdminPermission(UserAdminPermission.ADMIN, null);
327 			}
328 			sm.checkPermission(adminPermission);
329 		}
330 	}
331 
checkGetCredentialPermission(String credential)332 	public void checkGetCredentialPermission(String credential) {
333 		SecurityManager sm = System.getSecurityManager();
334 		if (sm != null) {
335 			sm.checkPermission(new org.osgi.service.useradmin.UserAdminPermission(credential, org.osgi.service.useradmin.UserAdminPermission.GET_CREDENTIAL));
336 		}
337 	}
338 
checkChangeCredentialPermission(String credential)339 	public void checkChangeCredentialPermission(String credential) {
340 		SecurityManager sm = System.getSecurityManager();
341 		if (sm != null) {
342 			sm.checkPermission(new org.osgi.service.useradmin.UserAdminPermission(credential, org.osgi.service.useradmin.UserAdminPermission.CHANGE_CREDENTIAL));
343 		}
344 	}
345 
checkChangePropertyPermission(String property)346 	public void checkChangePropertyPermission(String property) {
347 		SecurityManager sm = System.getSecurityManager();
348 		if (sm != null) {
349 			sm.checkPermission(new org.osgi.service.useradmin.UserAdminPermission(property, org.osgi.service.useradmin.UserAdminPermission.CHANGE_PROPERTY));
350 		}
351 	}
352 
checkAlive()353 	public void checkAlive() {
354 		if (!alive) {
355 			throw (new IllegalStateException(UserAdminMsg.USERADMIN_UNREGISTERED_EXCEPTION));
356 		}
357 	}
358 
359 }
360