Skip to content

Commit

Permalink
Implement UserCreateCommand and use from Web UI
Browse files Browse the repository at this point in the history
Fixes #23837
  • Loading branch information
vboctor committed Jan 20, 2018
1 parent c174056 commit f577d61
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 60 deletions.
38 changes: 37 additions & 1 deletion core/access_api.php
Expand Up @@ -54,6 +54,8 @@
require_api( 'string_api.php' );
require_api( 'user_api.php' );

use Mantis\Exceptions\ClientException;

# @global array $g_cache_access_matrix
$g_cache_access_matrix = array();

Expand Down Expand Up @@ -858,4 +860,38 @@ function access_can_see_handler_for_bug( BugData $p_bug, $p_user_id = null ) {
$p_bug->id );

return $t_can_view_handler;
}
}

/**
* Parse access level reference array parsed from json.
*
* @param array $p_access The access level
* @return integer The access level
* @throws ClientException Access level is invalid or not specified.
*/
function access_parse_array( array $p_access ) {
$t_access_levels_enum = config_get( 'access_levels_enum_string' );
$t_access_level = false;

if( isset( $p_access['id'] ) ) {
$t_access_level = (int)$p_access['id'];

# Make sure the provided id is valid
if( !MantisEnum::hasValue( $t_access_levels_enum, $t_access_level ) ) {
$t_access_level = false;
}
}

if( isset( $p_access['name'] ) ) {
$t_access_level = MantisEnum::getValue( $t_access_levels_enum, $p_access['name'] );
}

if( $t_access_level === false ) {
throw new ClientException(
'Invalid access level',
ERROR_INVALID_FIELD_VALUE,
array( 'access_level' ) );
}

return $t_access_level;
}
158 changes: 158 additions & 0 deletions core/commands/UserCreateCommand.php
@@ -0,0 +1,158 @@
<?php
# MantisBT - A PHP based bugtracking system

# MantisBT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# MantisBT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MantisBT. If not, see <http://www.gnu.org/licenses/>.

require_api( 'authentication_api.php' );
require_api( 'constant_inc.php' );
require_api( 'config_api.php' );
require_api( 'helper_api.php' );
require_api( 'user_api.php' );

use Mantis\Exceptions\ClientException;

/**
* A command that creates a user account.
*
* Sample:
* {
* "data": {
* "username": "vboctor",
* "password": "p@ssw0rd",
* "real_name": "Victor Boctor",
* "email": "vboctor@example.com",
* "access_level": { "name" => "developer" },
* "enabled": true,
* "protected": false
* }
* }
*/
class UserCreateCommand extends Command {
/**
* @var string user name
*/
private $username;

/**
* @var string user real name
*/
private $realname;

/**
* @var string user email address
*/
private $email;

/**
* @var string user password
*/
private $password;

/**
* @var boolean user can edit their information. Usually, true for shared accounts.
*/
private $protected;

/**
* @var boolean user account enabled for login.
*/
private $enabled;

/**
* Constructor
*
* @param array $p_data The command data.
*/
function __construct( array $p_data ) {
parent::__construct( $p_data );
}

/**
* Validate the data.
*/
function validate() {
# Ensure user has access level to create users
access_ensure_global_level( config_get_global( 'manage_user_threshold' ) );

# Access Level
$this->access_level = access_parse_array(
$this->payload(
'access_level',
array( 'id' => config_get_global( 'default_new_account_access_level' ) ) ) );

# Don't allow the creation of accounts with access levels higher than that of
# the user creating the account.
access_ensure_global_level( $this->access_level );

# Username and Real Name
$this->username = trim( $this->payload( 'username', '' ) );
if( is_blank( $this->username ) ) {
throw new ClientException( 'username must be specified', ERROR_EMPTY_FIELD );
}

$this->realname = string_normalize( $this->payload( 'real_name', '' ) );
user_ensure_name_valid( $this->username );
user_ensure_realname_unique( $this->username, $this->realname );

# Protected and Enabled Flags
$this->protected = $this->payload( 'protected', false );
$this->enabled = $this->payload( 'enabled', true );

# Email
$this->email = trim( $this->payload( 'email', '' ) );
email_ensure_not_disposable( $this->email );

# Password
$this->password = $this->payload( 'password', '' );
if( ( ON == config_get( 'send_reset_password' ) ) &&
( ON == config_get( 'enable_email_notification' ) ) ) {
# Check code will be sent to the user directly via email. Dummy password set to random
# Create random password
$this->password = auth_generate_random_password();
} else {
$this->password = $this->payload( 'password', auth_generate_random_password() );
}
}

/**
* Process the command.
*
* @returns array Command response
*/
protected function process() {
# Need to send the user creation mail in the tracker language, not in the creating admin's language
# Park the current language name until the user has been created
lang_push( config_get_global( 'default_language' ) );

# create the user
$t_admin_name = user_get_name( auth_get_current_user_id() );
user_create(
$this->username,
$this->password,
$this->email,
$this->access_level,
$this->protected,
$this->enabled,
$this->realname,
$t_admin_name );

# set language back to user language
lang_pop();

return array(
'id' => user_get_id_by_name( $this->username )
);
}
}

86 changes: 27 additions & 59 deletions manage_user_create.php
Expand Up @@ -25,40 +25,33 @@
* @uses core.php
* @uses access_api.php
* @uses authentication_api.php
* @uses config_api.php
* @uses constant_inc.php
* @uses email_api.php
* @uses form_api.php
* @uses gpc_api.php
* @uses helper_api.php
* @uses html_api.php
* @uses lang_api.php
* @uses print_api.php
* @uses string_api.php
* @uses user_api.php
* @uses utility_api.php
*/

require_once( 'core.php' );
require_api( 'access_api.php' );
require_api( 'authentication_api.php' );
require_api( 'config_api.php' );
require_api( 'constant_inc.php' );
require_api( 'email_api.php' );
require_api( 'form_api.php' );
require_api( 'gpc_api.php' );
require_api( 'helper_api.php' );
require_api( 'html_api.php' );
require_api( 'lang_api.php' );
require_api( 'print_api.php' );
require_api( 'string_api.php' );
require_api( 'user_api.php' );
require_api( 'utility_api.php' );

form_security_validate( 'manage_user_create' );

auth_reauthenticate();
access_ensure_global_level( config_get( 'manage_user_threshold' ) );

$f_username = gpc_get_string( 'username' );
$f_realname = gpc_get_string( 'realname', '' );
Expand All @@ -69,64 +62,40 @@
$f_protected = gpc_get_bool( 'protected' );
$f_enabled = gpc_get_bool( 'enabled' );

# check for empty username
$f_username = trim( $f_username );
if( is_blank( $f_username ) ) {
trigger_error( ERROR_EMPTY_FIELD, ERROR );
}

# Check the name for validity here so we do it before promting to use a
# blank password (don't want to prompt the user if the process will fail
# anyway)
# strip extra space from real name
$t_realname = string_normalize( $f_realname );
user_ensure_name_valid( $f_username );
user_ensure_realname_unique( $f_username, $f_realname );

if( $f_password != $f_password_verify ) {
trigger_error( ERROR_USER_CREATE_PASSWORD_MISMATCH, ERROR );
}

$f_email = trim( $f_email );
email_ensure_not_disposable( $f_email );

if( ( ON == config_get( 'send_reset_password' ) ) && ( ON == config_get( 'enable_email_notification' ) ) ) {
# Check code will be sent to the user directly via email. Dummy password set to random
# Create random password
$f_password = auth_generate_random_password();
} else {
# Password won't to be sent by email. It entered by the admin
# Now, if the password is empty, confirm that that is what we wanted
if( is_blank( $f_password ) ) {
helper_ensure_confirmed( lang_get( 'empty_password_sure_msg' ),
lang_get( 'empty_password_button' ) );
}
# Password won't to be sent by email. It entered by the admin
# Now, if the password is empty, confirm that that is what we wanted
if( is_blank( $f_password ) &&
( ON != config_get( 'send_reset_password' ) ) ||
( ON != config_get( 'enable_email_notification' ) ) ) {
helper_ensure_confirmed(
lang_get( 'empty_password_sure_msg' ),
lang_get( 'empty_password_button' ) );
}

# Don't allow the creation of accounts with access levels higher than that of
# the user creating the account.
access_ensure_global_level( $f_access_level );

# Need to send the user creation mail in the tracker language, not in the creating admin's language
# Park the current language name until the user has been created
lang_push( config_get_global( 'default_language' ) );

# create the user
$t_admin_name = user_get_name( auth_get_current_user_id() );
$t_cookie = user_create( $f_username, $f_password, $f_email, $f_access_level, $f_protected, $f_enabled, $t_realname, $t_admin_name );

# set language back to user language
lang_pop();
$t_data = array(
'query' => array(),
'payload' => array(
'username' => $f_username,
'email' => $f_email,
'access_level' => array( 'id' => $f_access_level ),
'real_name' => $f_realname,
'password' => $f_password,
'protected' => $f_protected,
'enabled' => $f_enabled
)
);

$t_command = new UserCreateCommand( $t_data );
$t_result = $t_command->execute();

form_security_purge( 'manage_user_create' );

if( $t_cookie === false ) {
$t_redirect_url = 'manage_user_page.php';
} else {
# ok, we created the user, get the row again
$t_user_id = user_get_id_by_name( $f_username );
$t_redirect_url = 'manage_user_edit_page.php?user_id=' . $t_user_id;
}
$t_user_id = $t_result['id'];
$t_redirect_url = 'manage_user_edit_page.php?user_id=' . $t_user_id;

layout_page_header( null, $t_redirect_url );

Expand All @@ -137,8 +106,7 @@
. lang_get( 'created_user_part2' )
. ' <span class="bold">' . $t_access_level . '</span><br />';
html_operation_successful( $t_redirect_url, $t_message );
?>
</div>

<?php
echo '</div>';

layout_page_end();

0 comments on commit f577d61

Please sign in to comment.