/* Copyright (c) 1995-2000, The Hypersonic SQL Group.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the Hypersonic SQL Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Hypersonic SQL Group.
*
*
* For work added by the HSQL Development Group:
*
* Copyright (c) 2001-2008, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb;
import org.hsqldb.lib.HashMappedList;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.SchemaManager.Schema;
// fredt@users 20020130 - patch 497872 by Nitin Chauhan - loop optimisation
// fredt@users 20020320 - doc 1.7.0 - update
// fredt@users 20021103 - patch 1.7.2 - allow for drop table, etc.
// fredt@users 20030613 - patch 1.7.2 - simplified data structures and reporting
// unsaved@users - patch 1.8.0 moved right managament to new classes
/**
*
* Manages the User objects for a Database instance.
* The special users PUBLIC_USER_NAME and SYSTEM_AUTHORIZATION_NAME
* are created and managed here. SYSTEM_AUTHORIZATION_NAME is also
* special in that the name is not kept in the user "list"
* (PUBLIC_USER_NAME is kept in the list because it's needed by MetaData
* routines via "listVisibleUsers(x, true)").
*
* Partly based on Hypersonic code.
*
* @author Thomas Mueller (Hypersonic SQL Group)
* @author boucherb@users
* @author fredt@users
*
* @version 1.8.0
* @since 1.7.2
* @see User
*/
class UserManager implements GrantConstants {
/**
* We keep a link to the SYSTEM_AUTHORIZATION_NAME user because it is
* the only User with no entry in the User map.
*/
User sysUser = null;
/**
* This object's set of User objects. <p>
*
* Note: The special _SYSTEM role
* is not included in this list but the special PUBLIC
* User object is kept in the list because it's needed by MetaData
* routines via "listVisibleUsers(x, true)".
*/
private HashMappedList userList;
private GranteeManager granteeManager;
/**
* Construction happens once for each Database object.
*
* Creates special users PUBLIC_USER_NAME and SYSTEM_AUTHORIZATION_NAME.
* Sets up association with the GranteeManager for this database.
*/
UserManager(Database database) throws HsqlException {
granteeManager = database.getGranteeManager();
userList = new HashMappedList();
createUser(GranteeManager.PUBLIC_ROLE_NAME, null);
sysUser = createUser(GranteeManager.SYSTEM_AUTHORIZATION_NAME, null);
// Don't know whether to grant ADMIN to SYS directly, or to grant
// role DBA. The former seems safer as it doesn't depend on any role.
//granteeManager.grant(SYSTEM_AUTHORIZATION_NAME, RoleManager.ADMIN_ROLE_NAME);
sysUser.getGrantee().setAdminDirect();
}
/**
* Creates a new User object under management of this object. <p>
*
* A set of constraints regarding user creation is imposed: <p>
*
* <OL>
* <LI>If the specified name is null, then an
* ASSERTION_FAILED exception is thrown stating that
* the name is null.
*
* <LI>If this object's collection already contains an element whose
* name attribute equals the name argument, then
* a GRANTEE_ALREADY_EXISTS exception is thrown.
* (This will catch attempts to create Reserved grantee names).
* </OL>
*/
User createUser(String name, String password) throws HsqlException {
if (name == null) {
Trace.doAssert(false, Trace.getMessage(Trace.NULL_NAME));
}
// TODO:
// checkComplexity(password);
// requires special: createSAUser(), createPublicUser()
// boucherb@users 20020815 - disallow user-land creation of SYS user
// -------------------------------------------------------
// This will throw an appropriate Trace if grantee already exists,
// regardless of whether the name is in any User, Role, etc. list.
Grantee g = granteeManager.addGrantee(name);
User u = new User(name, password, g);
// ONLY!! SYSTEM_AUTHORIZATION_NAME is not stored in our User list.
if (GranteeManager.SYSTEM_AUTHORIZATION_NAME.equals(name)) {
return u;
}
boolean success = userList.add(name, u);
if (!success) {
throw Trace.error(Trace.USER_ALREADY_EXISTS, name);
}
return u;
}
/**
* Attempts to drop a User object with the specified name
* from this object's set. <p>
*
* A successful drop action consists of: <p>
*
* <UL>
*
* <LI>removing the User object with the specified name
* from the set.
*
* <LI>revoking all rights from the removed object<br>
* (this ensures that in case there are still references to the
* just dropped User object, those references
* cannot be used to erronously access database objects).
*
* </UL> <p>
*
*/
void dropUser(String name) throws HsqlException {
boolean reservedUser = GranteeManager.isReserved(name);
Trace.check(!reservedUser, Trace.NONMOD_ACCOUNT, name);
boolean result = granteeManager.removeGrantee(name);
Trace.check(result, Trace.NO_SUCH_GRANTEE, name);
User u = (User) userList.remove(name);
Trace.check(u != null, Trace.USER_NOT_FOUND, name);
}
/**
* Returns the User object with the specified name and
* password from this object's set.
*/
User getUser(String name, String password) throws HsqlException {
if (name == null) {
name = "";
}
if (password == null) {
password = "";
}
// Don't have to worry about SYSTEM_AUTHORIZATION_NAME, since get()
// will fail below (because it's not in the list).
if (name.equals(GranteeManager.PUBLIC_ROLE_NAME)) {
throw Trace.error(Trace.ACCESS_IS_DENIED);
}
name = name.toUpperCase();
password = password.toUpperCase();
User u = get(name);
u.checkPassword(password);
return u;
}
/**
* Retrieves this object's set of User objects as
* an HsqlArrayList. <p>
*/
HashMappedList getUsers() {
return userList;
}
boolean exists(String name) {
return userList.get(name) == null ? false
: true;
}
/**
* Returns the User object identified by the
* name argument. <p>
*/
User get(String name) throws HsqlException {
User u = (User) userList.get(name);
if (u == null) {
throw Trace.error(Trace.USER_NOT_FOUND, name);
}
return u;
}
/**
* Retrieves the <code>User</code> objects representing the database
* users that are visible to the <code>User</code> object
* represented by the <code>session</code> argument. <p>
*
* If the <code>session</code> argument's <code>User</code> object
* attribute has isAdmin() true (directly or by virtue of a Role),
* then all of the
* <code>User</code> objects in this collection are considered visible.
* Otherwise, only this object's special <code>PUBLIC</code>
* <code>User</code> object attribute and the session <code>User</code>
* object, if it exists in this collection, are considered visible. <p>
*
* @param session The <code>Session</code> object used to determine
* visibility
* @param andPublicUser whether to include the special <code>PUBLIC</code>
* <code>User</code> object in the retrieved list
* @return a list of <code>User</code> objects visible to
* the <code>User</code> object contained by the
* <code>session</code> argument.
*
*/
HsqlArrayList listVisibleUsers(Session session, boolean andPublicUser) {
HsqlArrayList list;
User user;
boolean isAdmin;
String sessName;
String userName;
list = new HsqlArrayList();
isAdmin = session.isAdmin();
sessName = session.getUsername();
if (userList == null || userList.size() == 0) {
return list;
}
for (int i = 0; i < userList.size(); i++) {
user = (User) userList.get(i);
if (user == null) {
continue;
}
userName = user.getName();
if (GranteeManager.PUBLIC_ROLE_NAME.equals(userName)) {
if (andPublicUser) {
list.add(user);
}
} else if (isAdmin) {
list.add(user);
} else if (sessName.equals(userName)) {
list.add(user);
}
}
return list;
}
// Legacy wrappers
static String[] getRightsArray(int rights) {
return GranteeManager.getRightsArray(rights);
}
/**
* Removes all rights mappings for the database object identified by
* the dbobject argument from all Grantee objects in the set.
*/
void removeDbObject(Object dbobject) {
granteeManager.removeDbObject(dbobject);
}
/**
* Returns the specially constructed
* <code>SYSTEM_AUTHORIZATION_NAME</code>
* <code>User</code> object for the current <code>Database</code> object.
*
* @throws HsqlException - if the specified <code>Database</code>
* has no <code>SYS_AUTHORIZATION_NAME</code>
* <code>User</code> object.
* @return the <code>SYS_AUTHORIZATION_NAME</code>
* <code>User</code> object
*
*/
User getSysUser() {
return sysUser;
}
public synchronized void removeSchemaReference(Schema schema) {
for (int i = 0; i < userList.size(); i++) {
User user = (User) userList.get(i);
if (user.getInitialSchema() == schema.name) {
user.setInitialSchema(null);
}
}
}
}