/* Copyright (c) 2001-2019, 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.rights;

import org.hsqldb.Database;
import org.hsqldb.HsqlException;
import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.Routine;
import org.hsqldb.Schema;
import org.hsqldb.SchemaObject;
import org.hsqldb.Session;
import org.hsqldb.SqlInvariants;
import org.hsqldb.Tokens;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.HashMappedList;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.result.Result;

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)").
Author:Campbell Burnet (campbell-burnet@users dot sourceforge.net), Fred Toussi (fredt@users dot sourceforge.net)
See Also:
Version:2.5.0
Since:1.7.2
/** * 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)"). * * @author Campbell Burnet (campbell-burnet@users dot sourceforge.net) * @author Fred Toussi (fredt@users dot sourceforge.net) * * @version 2.5.0 * @since 1.7.2 * @see User */
public final class UserManager {
This object's set of User objects.

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)".

/** * 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;
The function for password complexity.
/** * The function for password complexity. */
Routine pwCheckFunction; Routine extAuthenticationFunction;
Construction happens once for each Database instance. Creates special users PUBLIC_USER_NAME and SYSTEM_AUTHORIZATION_NAME. Sets up association with the GranteeManager for this database.
/** * Construction happens once for each Database instance. * * Creates special users PUBLIC_USER_NAME and SYSTEM_AUTHORIZATION_NAME. * Sets up association with the GranteeManager for this database. */
public UserManager(Database database) { granteeManager = database.getGranteeManager(); userList = new HashMappedList(); }
Creates a new User object under management of this object.

A set of constraints regarding user creation is imposed:

  1. If the specified name is null, then an ASSERTION_FAILED exception is thrown stating that the name is null.
  2. 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).
/** * 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> */
public User createUser(Session session, HsqlName name, String password, boolean isDigest) { // This will throw an appropriate exception if grantee already exists, // regardless of whether the name is in any User, Role, etc. list. User user = granteeManager.addUser(name); if (session == null) { user.setPassword(password, isDigest); } else { try { setPassword(session, user, password, isDigest); } catch (HsqlException e) { granteeManager.removeNewUser(name); throw e; } } // this cannot fail userList.add(name.name, user); return user; } public void setPassword(Session session, User user, String password, boolean isDigest) { if (!isDigest && !checkComplexity(session, password)) { throw Error.error(ErrorCode.PASSWORD_COMPLEXITY); } // requires: UserManager.createSAUser(), UserManager.createPublicUser() user.setPassword(password, isDigest); } public boolean checkComplexity(Session session, String password) { if (session == null || pwCheckFunction == null) { return true; } Result result = pwCheckFunction.invoke(session, new Object[]{ password }, null, true); Boolean check = (Boolean) result.getValueObject(); if (check == null || !check.booleanValue()) { return false; } return true; }
Attempts to drop a User object with the specified name from this object's set.

A successful drop action consists of:

  • removing the User object with the specified name from the set.
  • revoking all rights from the removed User
    (this ensures that in case there are still references to the just dropped User object, those references cannot be used to erroneously access database objects).

/** * 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 User<br> * (this ensures that in case there are still references to the * just dropped User object, those references * cannot be used to erroneously access database objects). * * </UL> <p> * */
public void dropUser(String name) { boolean reservedUser = GranteeManager.isReserved(name); if (reservedUser) { throw Error.error(ErrorCode.X_28502, name); } boolean result = granteeManager.removeGrantee(name); if (!result) { throw Error.error(ErrorCode.X_28501, name); } User user = (User) userList.remove(name); if (user == null) { throw Error.error(ErrorCode.X_28501, name); } } public void createFirstUser(String username, String password) { boolean isQuoted = true; if (username.equalsIgnoreCase("SA")) { username = "SA"; isQuoted = false; } HsqlName name = granteeManager.database.nameManager.newHsqlName(username, isQuoted, SchemaObject.GRANTEE); User user = createUser(null, name, password, false); user.isLocalOnly = true; granteeManager.grant(name.name, SqlInvariants.DBA_ADMIN_ROLE_NAME, granteeManager.getDBARole()); }
Returns the User object with the specified name and password from this object's set.
/** * Returns the User object with the specified name and * password from this object's set. */
public User getUser(String name, String password) { if (name == null) { name = ""; } if (password == null) { password = ""; } User user = (User) userList.get(name); boolean isLocal = user != null && user.isLocalOnly; if (extAuthenticationFunction == null || isLocal) { user = get(name); user.checkPassword(password); return user; } /* * Authentication returns String[]. When null, use the existing * user object only, with existing privileges. * When not null, ignore if user exists. Otherwise create a user and * assign the list of roles to the user. */ Result result = extAuthenticationFunction.invokeJavaMethodDirect(new String[] { granteeManager.database.getNameString(), name, password }); if (result.isError()) { throw Error.error(ErrorCode.X_28501, result.getMainString()); } Object[] roles = (Object[]) result.getValueObject(); if (user == null) { HsqlName hsqlName = granteeManager.database.nameManager.newHsqlName(name, true, SchemaObject.GRANTEE); user = createUser(null, hsqlName, "", false); user.isExternalOnly = true; } if (roles == null) { user.updateAllRights(); return user; } // this clears all existing privileges of the user user.clearPrivileges(); // assigns the roles to the user for (int i = 0; i < roles.length; i++) { try { Grantee role = granteeManager.getRole((String) roles[i]); user.grant(role); } catch (HsqlException e) {} } user.updateAllRights(); for (int i = 0; i < roles.length; i++) { Schema schema = granteeManager.database.schemaManager.findSchema( (String) roles[i]); if (schema != null) { user.setInitialSchema(schema.getName()); break; } } return user; }
Retrieves this object's set of User objects as an associative list.
/** * Retrieves this object's set of User objects as * an associative list. */
public HashMappedList getUsers() { return userList; } public boolean exists(String name) { return userList.get(name) == null ? false : true; }
Returns the User object identified by the name argument.
/** * Returns the User object identified by the * name argument. */
public User get(String name) { User user = (User) userList.get(name); if (user == null) { throw Error.error(ErrorCode.X_28501, name); } return user; }
Retrieves the User objects representing the database users that are visible to the User object represented by the session argument.

If the session argument's User object attribute has isAdmin() true (directly or by virtue of a Role), then all of the User objects in this collection are considered visible. Otherwise, only this object's special PUBLIC User object attribute and the session User object, if it exists in this collection, are considered visible.

Params:
  • session – The Session object used to determine visibility
Returns:a list of User objects visible to the User object contained by the session argument.
/** * 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 * @return a list of <code>User</code> objects visible to * the <code>User</code> object contained by the * <code>session</code> argument. * */
public HsqlArrayList listVisibleUsers(Session session) { HsqlArrayList list; User user; boolean isAdmin; String sessionName; String userName; list = new HsqlArrayList(); isAdmin = session.isAdmin(); sessionName = 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().getNameString(); if (isAdmin) { list.add(user); } else if (sessionName.equals(userName)) { list.add(user); } } return list; }
Returns the specially constructed SYSTEM_AUTHORIZATION_NAME User object for the current Database object.
Returns:the SYS_AUTHORIZATION_NAME User object
/** * Returns the specially constructed * <code>SYSTEM_AUTHORIZATION_NAME</code> * <code>User</code> object for the current <code>Database</code> object. * * @return the <code>SYS_AUTHORIZATION_NAME</code> * <code>User</code> object * */
public User getSysUser() { return GranteeManager.systemAuthorisation; } public synchronized void removeSchemaReference(HsqlName schemaName) { for (int i = 0; i < userList.size(); i++) { User user = (User) userList.get(i); HsqlName schema = user.getInitialSchema(); if (schema == null) { continue; } if (schemaName.equals(schema)) { user.setInitialSchema(null); } } } public void setPasswordCheckFunction(Routine function) { pwCheckFunction = function; } public void setExtAuthenticationFunction(Routine function) { extAuthenticationFunction = function; } public String[] getInitialSchemaSQL() { HsqlArrayList list = new HsqlArrayList(userList.size()); for (int i = 0; i < userList.size(); i++) { User user = (User) userList.get(i); if (user.isSystem) { continue; } HsqlName name = user.getInitialSchema(); if (name == null) { continue; } list.add(user.getInitialSchemaSQL()); } String[] array = new String[list.size()]; list.toArray(array); return array; } public String[] getAuthenticationSQL() { HsqlArrayList list = new HsqlArrayList(); String[] array; if (pwCheckFunction != null) { StringBuilder sb = new StringBuilder(); sb.append(Tokens.T_SET).append(' ').append(Tokens.T_DATABASE); sb.append(' ').append(Tokens.T_PASSWORD).append(' '); sb.append(Tokens.T_CHECK).append(' ').append(Tokens.T_FUNCTION); sb.append(' '); sb.append(pwCheckFunction.getSQLBodyDefinition()); list.add(sb.toString()); } if (extAuthenticationFunction != null) { StringBuilder sb = new StringBuilder(); sb.append(Tokens.T_SET).append(' ').append(Tokens.T_DATABASE); sb.append(' ').append(Tokens.T_AUTHENTICATION).append(' '); sb.append(Tokens.T_FUNCTION).append(' '); sb.append(extAuthenticationFunction.getSQLBodyDefinition()); list.add(sb.toString()); } array = new String[list.size()]; list.toArray(array); return array; } }