- back end: extend the access control system for remote job submission

and other operations.
    You can now designate a user as "manager" for a particular app.
    They can then:
    - control job-submit permissions for that app
    - deprecate/undeprecate versions of the app.
    - abort jobs for that app

    You can also designate a user a manage for the project.
    They can then edit permissions and quotas,
    as well as performing the app-specific functions for all apps.

    This is described here:
    http://boinc.berkeley.edu/trac/wiki/MultiUser#Accesscontrol

    This required some changes to the DB schema.


svn path=/trunk/boinc/; revision=24250
This commit is contained in:
David Anderson 2011-09-21 21:26:00 +00:00
parent 11c9b6015e
commit 9d2ba11e09
13 changed files with 928 additions and 350 deletions

View File

@ -6289,3 +6289,42 @@ David 20 Sept 2011
scheduler_op.cpp,h
samples/example_app/
uc2.php
David 21 Sept 2011
- back end: extend the access control system for remote job submission
and other operations.
You can now designate a user as "manager" for a particular app.
They can then:
- control job-submit permissions for that app
- deprecate/undeprecate versions of the app.
- abort jobs for that app
You can also designate a user a manage for the project.
They can then edit permissions and quotas,
as well as performing the app-specific functions for all apps.
This is described here:
http://boinc.berkeley.edu/trac/wiki/MultiUser#Accesscontrol
This required some changes to the DB schema.
db/
schema.sql
tools/
manage_privileges
html/
inc/
submit.inc
submit_util.inc (new)
result.inc
ops/
submit_permissions.php (removed)
db_update.php
user/
manage_project.php (new)
submit_example.php
manage.php (new)
manage_app.php (new)
submit.php
py/Boinc/
setup_project.py

View File

@ -30,11 +30,11 @@
*/
create table platform (
id integer not null auto_increment,
create_time integer not null,
name varchar(254) not null,
user_friendly_name varchar(254) not null,
deprecated tinyint not null default 0,
id integer not null auto_increment,
create_time integer not null,
name varchar(254) not null,
user_friendly_name varchar(254) not null,
deprecated tinyint not null default 0,
primary key (id)
) engine=InnoDB;
@ -56,153 +56,153 @@ create table app (
) engine=InnoDB;
create table app_version (
id integer not null auto_increment,
create_time integer not null,
appid integer not null,
version_num integer not null,
platformid integer not null,
xml_doc mediumblob,
min_core_version integer not null default 0,
max_core_version integer not null default 0,
deprecated tinyint not null default 0,
plan_class varchar(254) not null default '',
pfc_n double not null default 0,
pfc_avg double not null default 0,
pfc_scale double not null default 0,
expavg_credit double not null default 0,
expavg_time double not null default 0,
id integer not null auto_increment,
create_time integer not null,
appid integer not null,
version_num integer not null,
platformid integer not null,
xml_doc mediumblob,
min_core_version integer not null default 0,
max_core_version integer not null default 0,
deprecated tinyint not null default 0,
plan_class varchar(254) not null default '',
pfc_n double not null default 0,
pfc_avg double not null default 0,
pfc_scale double not null default 0,
expavg_credit double not null default 0,
expavg_time double not null default 0,
primary key (id)
) engine=InnoDB;
create table user (
id integer not null auto_increment,
create_time integer not null,
email_addr varchar(254) not null,
name varchar(254),
authenticator varchar(254),
country varchar(254),
postal_code varchar(254),
total_credit double not null,
expavg_credit double not null,
expavg_time double not null,
global_prefs blob,
project_prefs blob,
teamid integer not null,
venue varchar(254) not null,
url varchar(254),
send_email smallint not null,
show_hosts smallint not null,
posts smallint not null,
id integer not null auto_increment,
create_time integer not null,
email_addr varchar(254) not null,
name varchar(254),
authenticator varchar(254),
country varchar(254),
postal_code varchar(254),
total_credit double not null,
expavg_credit double not null,
expavg_time double not null,
global_prefs blob,
project_prefs blob,
teamid integer not null,
venue varchar(254) not null,
url varchar(254),
send_email smallint not null,
show_hosts smallint not null,
posts smallint not null,
-- reused: salt for weak auth
seti_id integer not null,
seti_nresults integer not null,
seti_last_result_time integer not null,
seti_total_cpu double not null,
signature varchar(254),
seti_id integer not null,
seti_nresults integer not null,
seti_last_result_time integer not null,
seti_total_cpu double not null,
signature varchar(254),
-- deprecated
has_profile smallint not null,
cross_project_id varchar(254) not null,
passwd_hash varchar(254) not null,
email_validated smallint not null,
donated smallint not null,
has_profile smallint not null,
cross_project_id varchar(254) not null,
passwd_hash varchar(254) not null,
email_validated smallint not null,
donated smallint not null,
primary key (id)
) engine=InnoDB;
create table team (
id integer not null auto_increment,
create_time integer not null,
userid integer not null,
name varchar(254) not null,
name_lc varchar(254),
url varchar(254),
type integer not null,
name_html varchar(254),
description text,
nusers integer not null, /* temp */
country varchar(254),
total_credit double not null, /* temp */
expavg_credit double not null, /* temp */
expavg_time double not null,
seti_id integer not null,
ping_user integer not null default 0,
ping_time integer unsigned not null default 0,
joinable tinyint not null default 1,
id integer not null auto_increment,
create_time integer not null,
userid integer not null,
name varchar(254) not null,
name_lc varchar(254),
url varchar(254),
type integer not null,
name_html varchar(254),
description text,
nusers integer not null, /* temp */
country varchar(254),
total_credit double not null, /* temp */
expavg_credit double not null, /* temp */
expavg_time double not null,
seti_id integer not null,
ping_user integer not null default 0,
ping_time integer unsigned not null default 0,
joinable tinyint not null default 1,
primary key (id)
) engine=MyISAM;
create table host (
id integer not null auto_increment,
create_time integer not null,
userid integer not null,
rpc_seqno integer not null,
rpc_time integer not null,
total_credit double not null,
expavg_credit double not null,
expavg_time double not null,
id integer not null auto_increment,
create_time integer not null,
userid integer not null,
rpc_seqno integer not null,
rpc_time integer not null,
total_credit double not null,
expavg_credit double not null,
expavg_time double not null,
timezone integer not null,
domain_name varchar(254),
serialnum varchar(254),
last_ip_addr varchar(254),
nsame_ip_addr integer not null,
timezone integer not null,
domain_name varchar(254),
serialnum varchar(254),
last_ip_addr varchar(254),
nsame_ip_addr integer not null,
on_frac double not null,
connected_frac double not null,
active_frac double not null,
cpu_efficiency double not null,
duration_correction_factor double not null,
p_ncpus integer not null,
p_vendor varchar(254),
p_model varchar(254),
p_fpops double not null,
p_iops double not null,
p_membw double not null,
on_frac double not null,
connected_frac double not null,
active_frac double not null,
cpu_efficiency double not null,
duration_correction_factor double not null,
p_ncpus integer not null,
p_vendor varchar(254),
p_model varchar(254),
p_fpops double not null,
p_iops double not null,
p_membw double not null,
os_name varchar(254),
os_version varchar(254),
os_name varchar(254),
os_version varchar(254),
m_nbytes double not null,
m_cache double not null,
m_swap double not null,
m_nbytes double not null,
m_cache double not null,
m_swap double not null,
d_total double not null,
d_free double not null,
d_boinc_used_total double not null,
d_boinc_used_project double not null,
d_boinc_max double not null,
d_total double not null,
d_free double not null,
d_boinc_used_total double not null,
d_boinc_used_project double not null,
d_boinc_max double not null,
n_bwup double not null,
n_bwdown double not null,
n_bwup double not null,
n_bwdown double not null,
credit_per_cpu_sec double not null,
venue varchar(254) not null,
nresults_today integer not null,
avg_turnaround double not null,
host_cpid varchar(254),
external_ip_addr varchar(254),
max_results_day integer not null,
error_rate double not null default 0,
credit_per_cpu_sec double not null,
venue varchar(254) not null,
nresults_today integer not null,
avg_turnaround double not null,
host_cpid varchar(254),
external_ip_addr varchar(254),
max_results_day integer not null,
error_rate double not null default 0,
primary key (id)
) engine=InnoDB;
-- see comments in boinc_db.h
create table host_app_version (
host_id integer not null,
app_version_id integer not null,
pfc_n double not null,
pfc_avg double not null,
et_n double not null,
et_avg double not null,
et_var double not null,
et_q double not null,
max_jobs_per_day integer not null,
n_jobs_today integer not null,
turnaround_n double not null,
turnaround_avg double not null,
turnaround_var double not null,
turnaround_q double not null,
consecutive_valid integer not null
host_id integer not null,
app_version_id integer not null,
pfc_n double not null,
pfc_avg double not null,
et_n double not null,
et_avg double not null,
et_var double not null,
et_q double not null,
max_jobs_per_day integer not null,
n_jobs_today integer not null,
turnaround_n double not null,
turnaround_avg double not null,
turnaround_var double not null,
turnaround_q double not null,
consecutive_valid integer not null
) engine = InnoDB;
/*
@ -212,166 +212,176 @@ create table host_app_version (
* is stored in the XML doc
*/
create table workunit (
id integer not null auto_increment,
create_time integer not null,
appid integer not null,
name varchar(254) not null,
xml_doc blob,
batch integer not null,
rsc_fpops_est double not null,
rsc_fpops_bound double not null,
rsc_memory_bound double not null,
rsc_disk_bound double not null,
need_validate smallint not null,
canonical_resultid integer not null,
canonical_credit double not null,
transition_time integer not null,
delay_bound integer not null,
error_mask integer not null,
file_delete_state integer not null,
assimilate_state integer not null,
hr_class integer not null,
opaque double not null,
min_quorum integer not null,
target_nresults integer not null,
max_error_results integer not null,
max_total_results integer not null,
max_success_results integer not null,
result_template_file varchar(63) not null,
priority integer not null,
mod_time timestamp,
rsc_bandwidth_bound double not null,
fileset_id integer not null,
app_version_id integer not null,
id integer not null auto_increment,
create_time integer not null,
appid integer not null,
name varchar(254) not null,
xml_doc blob,
batch integer not null,
rsc_fpops_est double not null,
rsc_fpops_bound double not null,
rsc_memory_bound double not null,
rsc_disk_bound double not null,
need_validate smallint not null,
canonical_resultid integer not null,
canonical_credit double not null,
transition_time integer not null,
delay_bound integer not null,
error_mask integer not null,
file_delete_state integer not null,
assimilate_state integer not null,
hr_class integer not null,
opaque double not null,
min_quorum integer not null,
target_nresults integer not null,
max_error_results integer not null,
max_total_results integer not null,
max_success_results integer not null,
result_template_file varchar(63) not null,
priority integer not null,
mod_time timestamp,
rsc_bandwidth_bound double not null,
fileset_id integer not null,
app_version_id integer not null,
primary key (id)
) engine=InnoDB;
create table result (
id integer not null auto_increment,
create_time integer not null,
workunitid integer not null,
server_state integer not null,
outcome integer not null,
client_state integer not null,
hostid integer not null,
userid integer not null,
report_deadline integer not null,
sent_time integer not null,
received_time integer not null,
name varchar(254) not null,
cpu_time double not null,
xml_doc_in blob,
xml_doc_out blob,
stderr_out blob,
batch integer not null,
file_delete_state integer not null,
validate_state integer not null,
claimed_credit double not null,
granted_credit double not null,
opaque double not null,
random integer not null,
app_version_num integer not null,
appid integer not null,
exit_status integer not null,
teamid integer not null,
priority integer not null,
mod_time timestamp,
elapsed_time double not null,
flops_estimate double not null,
app_version_id integer not null,
id integer not null auto_increment,
create_time integer not null,
workunitid integer not null,
server_state integer not null,
outcome integer not null,
client_state integer not null,
hostid integer not null,
userid integer not null,
report_deadline integer not null,
sent_time integer not null,
received_time integer not null,
name varchar(254) not null,
cpu_time double not null,
xml_doc_in blob,
xml_doc_out blob,
stderr_out blob,
batch integer not null,
file_delete_state integer not null,
validate_state integer not null,
claimed_credit double not null,
granted_credit double not null,
opaque double not null,
random integer not null,
app_version_num integer not null,
appid integer not null,
exit_status integer not null,
teamid integer not null,
priority integer not null,
mod_time timestamp,
elapsed_time double not null,
flops_estimate double not null,
app_version_id integer not null,
runtime_outlier tinyint not null,
primary key (id)
) engine=InnoDB;
-- see boinc_db.h for doc
create table batch (
id serial primary key,
user_id integer not null,
create_time integer not null,
logical_start_time double not null,
logical_end_time double not null,
est_completion_time double not null,
njobs integer not null,
fraction_done double not null,
nerror_jobs integer not null,
state integer not null,
completion_time double not null,
credit_estimate double not null,
credit_canonical double not null,
credit_total double not null,
name varchar(255) not null,
app_id integer not null
id serial primary key,
user_id integer not null,
create_time integer not null,
logical_start_time double not null,
logical_end_time double not null,
est_completion_time double not null,
njobs integer not null,
fraction_done double not null,
nerror_jobs integer not null,
state integer not null,
completion_time double not null,
credit_estimate double not null,
credit_canonical double not null,
credit_total double not null,
name varchar(255) not null,
app_id integer not null
) engine = InnoDB;
-- permissions for job submission
--
create table user_submit (
user_id integer not null,
quota double not null,
logical_start_time double not null,
all_apps tinyint not null,
create_apps tinyint not null,
create_app_versions tinyint not null
user_id integer not null,
quota double not null,
logical_start_time double not null,
submit_all tinyint not null,
-- can submit jobs to any app
manage_all tinyint not null,
-- manager privileges for all apps
-- grant/revoke permissions (except manage), change quotas
-- create apps
) engine = InnoDB;
-- (user, app) submit permissions
-- The existence of the record implies permission to submit jobs
--
create table user_submit_app (
user_id integer not null,
app_id integer not null
user_id integer not null,
app_id integer not null
manage tinyint not null
-- can
-- create/deprecated app versions of this app
-- grant/revoke permissions (except admin) this app
-- abort their jobs
) engine = InnoDB;
-- the following are used to implement trickle messages
create table msg_from_host (
id integer not null auto_increment,
create_time integer not null,
hostid integer not null,
variety varchar(254) not null,
handled smallint not null,
xml mediumtext,
id integer not null auto_increment,
create_time integer not null,
hostid integer not null,
variety varchar(254) not null,
handled smallint not null,
xml mediumtext,
primary key (id)
) engine=InnoDB;
create table msg_to_host (
id integer not null auto_increment,
create_time integer not null,
hostid integer not null,
variety varchar(254) not null,
handled smallint not null,
xml mediumtext,
id integer not null auto_increment,
create_time integer not null,
hostid integer not null,
variety varchar(254) not null,
handled smallint not null,
xml mediumtext,
primary key (id)
) engine=InnoDB;
-- An assignment of a WU to a specific host, user, or team, or to all hosts
--
create table assignment (
id integer not null auto_increment,
create_time integer not null,
target_id integer not null,
id integer not null auto_increment,
create_time integer not null,
target_id integer not null,
-- ID of target entity (see below)
target_type integer not null,
target_type integer not null,
-- 0=none, 1=host, 2=user, 3=team
multi tinyint not null,
multi tinyint not null,
-- 0=single host, 1=all hosts in set
workunitid integer not null,
resultid integer not null,
workunitid integer not null,
resultid integer not null,
-- if not multi, the result
primary key (id)
) engine = InnoDB;
-- the following not used for anything right now
create table state_counts (
appid integer not null,
last_update_time integer not null,
result_server_state_2 integer not null,
result_server_state_4 integer not null,
result_file_delete_state_1 integer not null,
result_file_delete_state_2 integer not null,
appid integer not null,
last_update_time integer not null,
result_server_state_2 integer not null,
result_server_state_4 integer not null,
result_file_delete_state_1 integer not null,
result_file_delete_state_2 integer not null,
result_server_state_5_and_file_delete_state_0 integer not null,
workunit_need_validate_1 integer not null,
workunit_assimilate_state_1 integer not null,
workunit_file_delete_state_1 integer not null,
workunit_file_delete_state_2 integer not null,
workunit_file_delete_state_1 integer not null,
workunit_file_delete_state_2 integer not null,
primary key (appid)
) engine=MyISAM;
@ -382,16 +392,16 @@ create table state_counts (
-- user profile (description, pictures)
--
create table profile (
userid integer not null,
language varchar(254),
response1 text,
response2 text,
has_picture smallint not null,
recommend integer not null,
reject integer not null,
posts integer not null,
uotd_time integer,
verification integer not null,
userid integer not null,
language varchar(254),
response1 text,
response2 text,
has_picture smallint not null,
recommend integer not null,
reject integer not null,
posts integer not null,
uotd_time integer,
verification integer not null,
-- UOD screening status: -1 denied, 0 unrated, 1 approved
primary key (userid)
) engine=MyISAM;

View File

@ -19,6 +19,8 @@
require_once("../inc/translation.inc");
require_once("../inc/dir_hier.inc");
// used by app_version_string(), see below
//
$apps = array();
$app_versions = array();
@ -539,39 +541,6 @@ function result_navigation($info, $where_clause) {
return $x;
}
function get_outfile_names($result) {
$names = array();
$xml = "<a>".$result->xml_doc_out."</a>";
$r = simplexml_load_string($xml);
if (!$r) return $names;
foreach ($r->file_info as $fi) {
$names[] = (string)($fi->name);
}
return $names;
}
function get_outfile_paths($result) {
$fanout = parse_config(get_config(), "<uldl_dir_fanout>");
$upload_dir = parse_config(get_config(), "<upload_dir>");
$paths = array();
$xml = "<a>".$result->xml_doc_out."</a>";
$r = simplexml_load_string($xml);
if (!$r) return $paths;
foreach ($r->file_info as $fi) {
$path = dir_hier_path((string)($fi->name), $upload_dir, $fanout);
$paths[] = $path;
}
return $paths;
}
function abort_workunit($wu) {
BoincResult::update_aux(
"server_state=5, outcome=5 where server_state=2 and workunitid=$wu->id"
);
$wu->update("error_mask=error_mask|16");
}
$cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit
?>

View File

@ -106,17 +106,6 @@ function batch_xml_to_object($batch) {
return $b;
}
function batch_state_string($state) {
switch ($state) {
case BATCH_STATE_INIT: return "new";
case BATCH_STATE_IN_PROGRESS: return "in progress";
case BATCH_STATE_COMPLETE: return "completed";
case BATCH_STATE_ABORTED: return "aborted";
case BATCH_STATE_RETIRED: return "retired";
}
return "unknown state $state";
}
//// API functions follow
function boinc_estimate_batch($req) {

86
html/inc/submit_util.inc Normal file
View File

@ -0,0 +1,86 @@
<?php
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2011 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// utility functions for remote job submissions and control
require_once("../inc/submit_db.inc");
function get_outfile_names($result) {
$names = array();
$xml = "<a>".$result->xml_doc_out."</a>";
$r = simplexml_load_string($xml);
if (!$r) return $names;
foreach ($r->file_info as $fi) {
$names[] = (string)($fi->name);
}
return $names;
}
function get_outfile_paths($result) {
$fanout = parse_config(get_config(), "<uldl_dir_fanout>");
$upload_dir = parse_config(get_config(), "<upload_dir>");
$paths = array();
$xml = "<a>".$result->xml_doc_out."</a>";
$r = simplexml_load_string($xml);
if (!$r) return $paths;
foreach ($r->file_info as $fi) {
$path = dir_hier_path((string)($fi->name), $upload_dir, $fanout);
$paths[] = $path;
}
return $paths;
}
function abort_workunit($wu) {
BoincResult::update_aux(
"server_state=5, outcome=5 where server_state=2 and workunitid=$wu->id"
);
$wu->update("error_mask=error_mask|16");
}
function abort_batch($batch) {
$wus = BoincWorkunit::enum("batch=$batch->id");
foreach ($wus as $wu) {
abort_workunit($wu);
}
$batch->update("state=".BATCH_STATE_ABORTED);
return 0;
}
function retire_batch($batch) {
$wus = BoincWorkunit::enum("batch=$batch_id");
$now = time();
foreach ($wus as $wu) {
$wu->update("assimilate_state=2, transition_time=$now");
}
$batch->update("state=".BATCH_STATE_RETIRED);
}
function batch_state_string($state) {
switch ($state) {
case BATCH_STATE_INIT: return "new";
case BATCH_STATE_IN_PROGRESS: return "in progress";
case BATCH_STATE_COMPLETE: return "completed";
case BATCH_STATE_ABORTED: return "aborted";
case BATCH_STATE_RETIRED: return "retired";
}
return "unknown state $state";
}
?>

View File

@ -781,6 +781,21 @@ function update_9_15_2011() {
");
}
function update_9_20_2011() {
do_query("
alter table user_submit
drop column all_apps,
drop column create_apps,
drop column create_app_versions,
add submit_all tinyint not null,
add manage_all tinyint not null
");
do_query("
alter table user_submit_app
add manage tinyint not null
");
}
// Updates are done automatically if you use "upgrade".
//
// If you need to do updates manually,
@ -803,6 +818,9 @@ $db_updates = array (
array(23881, "update_7_26_2011"),
array(24137, "update_9_6_2011"),
array(24225, "update_9_15_2011"),
array(24248, "update_9_20_2011"),
);
?>

70
html/user/manage.php Normal file
View File

@ -0,0 +1,70 @@
<?php
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2011 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// top-level management page;
// shows links to the various functions available to the user.
// If the only option is managing a particular app,
// redirect to that page
require_once("../inc/submit_db.inc");
require_once("../inc/util.inc");
$user = get_logged_in_user();
$bus = BoincUserSubmit::lookup_userid($user->id);
if (!$bus) die("no access");
if ($bus->manage_all) {
page_head("Management functions");
echo "
<a href=manage_project.php>Project-wide management</a>
";
$apps = BoincApp::enum(null);
echo "
<p>Application-specific management:
<ul>
";
foreach ($apps as $app) {
echo "
<li><a href=manage_app.php?app_id=$app->id>$app->name</a>
";
}
echo "</ul>\n";
page_tail();
exit;
}
$apps = BoincUserSubmit::enum("user_id=$user->id and manage<>1");
switch (count($apps)) {
case 0:
error_page("Nothing to manage");
case 1:
$app = $apps[0];
Header("Location: manage_app.php?app_id=$app->id");
exit;
default:
page_head("Management functions");
foreach ($apps as $app) {
echo "
<p><a href=manage_app.php?app_id=$app->id>Manage $app->name</a>
";
}
page_tail();
}
?>

231
html/user/manage_app.php Normal file
View File

@ -0,0 +1,231 @@
<?php
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2011 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// app-specific management interface
error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('display_startup_errors', true);
require_once("../inc/submit_util.inc");
require_once("../inc/util.inc");
function main_page($app) {
page_head("Management functions for $app->name");
echo "
<a href=manage_app.php?app_id=$app->id&amp;action=app_version_form>Manage app versions</a>
<p>
<a href=manage_app.php?app_id=$app->id&amp;action=permissions_form>Manage user permissions</a>
<p>
<a href=manage_app.php?app_id=$app->id&amp;action=batches_form>Manage jobs</a>
";
page_tail();
}
function app_version_form($app) {
page_head("Manage app versions");
echo "
<form action=manage_app.php>
<input type=hidden name=action value=app_version_action>
<input type=hidden name=app_id value=$app->id>
";
$avs = BoincAppVersion::enum("appid=$app->id");
start_table();
table_header("platform", "plan class", "version#", "deprecated");
foreach ($avs as $av) {
$platform = BoincPlatform::lookup_id($av->platformid);
$c = $av->deprecated?"checked":"";
echo "
<tr>
<td>$platform->name</td>
<td>$av->plan_class</td>
<td>$av->version_num</td>
<td><input type=checkbox name=dep_$av->id $c></td>
</tr>
";
}
echo "
<tr>
<td><br></td>
<td><br></td>
<td><br></td>
<td><input type=submit value=Update></td>
</tr>
";
end_table();
echo "<form>\n";
page_tail();
}
function app_version_action($app) {
$avs = BoincAppVersion::enum("appid=$app->id");
foreach ($avs as $av) {
$x = get_str("dep_$av->id", true);
if ($x) {
if (!$av->deprecated) {
$av->update("deprecated=1");
}
} else {
if ($av->deprecated) {
$av->update("deprecated=0");
}
}
}
page_head("Update successful");
echo "
<a href=manage_app.php?app_id=$app->id>Return to application management page</a>
";
page_tail();
}
function permissions_form($app) {
page_head("Manage user permissions for $app->name");
echo "
<form action=manage_app.php>
<input type=hidden name=action value=permissions_action>
<input type=hidden name=app_id value=$app->id>
";
$busas = BoincUserSubmitApp::enum("app_id=$app->id");
start_table();
table_header("User", "Allowed to submit jobs to $app->name");
foreach ($busas as $busa) {
$user = BoincUser::lookup_id($busa->user_id);
echo "
<tr>
<td>$user->name ($user->id)</td>
<td><input type=checkbox name=user_$user->id checked></td>
</tr>
";
}
echo "
<tr>
<td>Add new user</td>
<td>User ID: <input name=new_user_id></td>
</tr>
<tr>
<td><br></td>
<td><input type=submit value=OK></td>
</tr>
";
end_table();
echo "<form>\n";
page_tail();
}
function permissions_action($app) {
$busas = BoincUserSubmitApp::enum("app_id=$app->id");
foreach ($busas as $busa) {
if (!get_str("user_$busa->user_id", true)) {
BoincUserSubmitApp::delete_user($busa->user_id);
}
}
$userid = get_int("new_user_id", true);
if ($userid) {
BoincUserSubmitApp::insert("(user_id, app_id) values ($userid, $app->id)");
}
page_head("Update successful");
echo "
<a href=manage_app.php?app_id=$app->id>Return to application management page</a>
";
page_tail();
}
function batches_form($app) {
page_head("Manage jobs for $app->name");
echo "
<form action=manage_app.php>
<input type=hidden name=action value=batches_action>
<input type=hidden name=app_id value=$app->id>
";
start_table();
table_header("Batch ID", "Submitter", "Submitted", "State", "# jobs", "Abort?");
$batches = BoincBatch::enum("app_id=$app->id");
foreach ($batches as $batch) {
$user = BoincUser::lookup_id($batch->user_id);
echo "<tr>
<td>$batch->id</td>
<td>$user->name</td>
<td>".time_str($batch->create_time)."</td>
<td>".batch_state_string($batch->state)."
<td>$batch->njobs</td>
<td><input type=checkbox name=abort_$batch->id></td>
</tr>
";
}
echo "<tr>
<td colspan=5>Abort all jobs for $app->name?</td>
<td><input type=checkbox name=abort_all></td>
</tr>
";
echo "<tr>
<td><br></td>
<td><br></td>
<td><br></td>
<td><input type=submit value=OK></td>
</tr>
";
end_table();
page_tail();
}
function batches_action($app) {
$batches = BoincBatch::enum("app_id=$app->id");
$abort_all = (get_str("abort_all", true));
foreach ($batches as $batch) {
if ($abort_all || get_str("abort_$batch->id", true)) {
abort_batch($batch);
}
}
page_head("Update successful");
echo "
<a href=manage_app.php?app_id=$app->id>Return to application management page</a>
";
page_tail();
}
$user = get_logged_in_user();
$app_id = get_int("app_id");
$app = BoincApp::lookup_id($app_id);
if (!$app) error_page("no such app");
$bus = BoincUserSubmit::lookup_userid($user->id);
if (!$bus) error_page("no access");
if (!$bus->manage_all) {
$busa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app_id");
if (!$busa || !$busa->manage) error_page("no access");
}
$action = get_str("action", true);
switch ($action) {
case "":
main_page($app); break;
case "app_version_form":
app_version_form($app); break;
case "app_version_action":
app_version_action($app); break;
case "permissions_form":
permissions_form($app); break;
case "permissions_action":
permissions_action($app); break;
case "batches_form":
batches_form($app); break;
case "batches_action":
batches_action($app); break;
default:
error_page("unknown action $action");
}
?>

View File

@ -17,21 +17,24 @@
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// Interface for controlling user permissions to submit jobs
// Interface for project-wide functions:
// - control user quotas and permissions to submit jobs
// - create apps
require_once("../inc/submit_db.inc");
require_once("../inc/util.inc");
require_once("../inc/util_ops.inc");
function user_row($u) {
$user = BoincUser::lookup_id($u->user_id);
echo "
<tr>
<td>$user->name<br>$user->email_addr</td>
<td>$user->name (ID: $user->id)
<a href=manage_project.php?action=edit_form&user_id=$u->user_id>Edit permissions</a>
</td>
";
echo "<td>";
if ($u->all_apps) {
echo "All\n";
if ($u->submit_all) {
echo "All applications\n";
} else {
$uas = BoincUserSubmitApp::enum("user_id=$u->user_id");
foreach ($uas as $ua) {
@ -42,46 +45,53 @@ function user_row($u) {
echo "</td>\n";
echo "<td>$u->quota</td>\n";
echo "<td>
<a href=submit_permissions.php?action=edit_form&user_id=$u->user_id>Edit</a>
</td>
</tr>
";
}
function handle_list() {
admin_page_head("User job submission permissions");
page_head("Project-wide management functions");
echo "<h3>User permissions and quotas</h3>
The following users are allowed to remotely submit jobs.
<p>
";
show_button("manage_project.php?action=add_form",
"Add user", "Allow a new user to submit jobs"
);
$us = BoincUserSubmit::enum("");
start_table();
table_header("User", "Applications", "Quota", "");
table_header("User", "Can submit jobs for", "Quota");
foreach ($us as $u) {
user_row($u);
}
end_table();
show_button("submit_permissions.php?action=add_form", "Add user", "Add user");
admin_page_tail();
page_tail();
}
function handle_edit_form() {
$user_id = get_int('user_id');
$user = BoincUser::lookup_id($user_id);
$usub = BoincUserSubmit::lookup_userid($user_id);
admin_page_head("Set permissions for $user->name");
page_head("Permissions for $user->name");
echo "
Can submit jobs for:
<form action=submit_permissions.php>
$user->name is allowed to submit jobs for:
<p>
<form action=manage_project.php>
<input type=hidden name=action value=edit_action>
<input type=hidden name=user_id value=$user_id>
";
if ($usub->all_apps) {
if ($usub->submit_all) {
$all_checked = "checked";
$not_all_checked = "";
} else {
$all_checked = "";
$not_all_checked = "checked";
}
echo "<input type=radio name=all_apps value=1 $all_checked> All apps
echo "<input type=radio name=submit_all value=1 $all_checked> All apps
<br>
<input type=radio name=all_apps value=0 $not_all_checked> Only selected apps:
<input type=radio name=submit_all value=0 $not_all_checked> Only selected apps:
";
$apps = BoincApp::enum("deprecated=0");
foreach ($apps as $app) {
@ -93,29 +103,28 @@ function handle_edit_form() {
$sav = $usub->create_app_versions?"checked":"";
$sa = $usub->create_apps?"checked":"";
echo "
<p>
<input type=checkbox name=create_app_versions $sav> Can create new versions of the above apps
<p>
<input type=checkbox name=create_apps $sa> Can create new apps
<p>
Quota: <input name=quota value=$q>
This determines how much computing capacity is allocated to $user->name.
<p>
<input type=submit value=OK>
</form>
<p>
<a href=manage_project.php>Return to project-wide management functions</a>
";
admin_page_tail();
page_tail();
}
function handle_edit_action() {
$user_id = get_int('user_id');
$us = BoincUserSubmit::lookup_userid($user_id);
if (!$us) admin_error_page("user not found");
if (!$us) error_page("user not found");
BoincUserSubmitApp::delete_user($user_id);
$all_apps = get_str('all_apps');
if ($all_apps) {
$us->update("all_apps=1");
$submit_all = get_str('submit_all');
if ($submit_all) {
$us->update("submit_all=1");
} else {
$us->update("all_apps=0");
$us->update("submit_all=0");
$apps = BoincApp::enum("deprecated=0");
foreach ($apps as $app) {
$x = "app_$app->id";
@ -128,39 +137,41 @@ function handle_edit_action() {
if ($quota != $us->quota) {
$us->update("quota=$quota");
}
$x = get_str('create_apps', true)?1:0;
$us->update("create_apps=$x");
$x = get_str('create_app_versions', true)?1:0;
$us->update("create_app_versions=$x");
admin_page_head("User permissions updated");
admin_page_tail();
page_head("Update successful");
echo "<a href=manage_project.php>Return to project-wide management functions</a>";
page_tail();
}
function handle_add_form() {
admin_page_head("Add user");
page_head("Add user");
echo "
<form action=submit_permissions.php>
<form action=manage_project.php>
<input type=hidden name=action value=add_action>
User ID: <input name=user_id>
<br>
<input type=submit value=OK>
</form>
";
admin_page_tail();
page_tail();
}
function handle_add_action() {
$user_id = get_int('user_id');
$user = BoincUser::lookup_id($user_id);
if (!$user) admin_error_page("no such user");
if (!$user) error_page("no such user");
$us = BoincUserSubmit::lookup_userid($user_id);
if (!$us) {
if (!BoincUserSubmit::insert("(user_id) values ($user_id)")) {
admin_error_page("Insert failed");
error_page("Insert failed");
}
}
header("Location: submit_permissions.php?action=edit_form&user_id=$user_id");
header("Location: manage_project.php?action=edit_form&user_id=$user_id");
}
$user = get_logged_in_user();
$bus = BoincUserSubmit::lookup_userid($user->id);
if (!$bus) {
die("no access");
}
$action = get_str('action', true);
@ -177,7 +188,7 @@ case 'edit_form':
case 'edit_action':
handle_edit_action(); break;
default:
admin_error_page("unknown action: $action");
error_page("unknown action: $action");
}
?>

View File

@ -24,6 +24,7 @@ require_once("../inc/submit_db.inc");
require_once("../inc/xml.inc");
require_once("../inc/dir_hier.inc");
require_once("../inc/result.inc");
require_once("../inc/submit_util.inc");
error_reporting(E_ALL);
ini_set('display_errors', true);
@ -41,7 +42,7 @@ function authenticate_user($r, $app) {
if (!$user) error("bad authenticator");
$user_submit = BoincUserSubmit::lookup_userid($user->id);
if (!$user_submit) error("no submit access");
if ($app && !$user_submit->all_apps) {
if ($app && !$user_submit->submit_all) {
$usa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id");
if (!$usa) {
error("no submit access");
@ -326,34 +327,25 @@ function query_job($r) {
echo "</job>\n";
}
function abort_batch($r) {
function handle_abort_batch($r) {
list($user, $user_submit) = authenticate_user($r, null);
$batch_id = (int)($r->batch_id);
$batch = BoincBatch::lookup_id($batch_id);
if ($batch->user_id != $user->id) {
error("not owner");
}
$wus = BoincWorkunit::enum("batch=$batch_id");
foreach ($wus as $wu) {
abort_workunit($wu);
}
$batch->update("state=".BATCH_STATE_ABORTED);
abort_batch($batch);
echo "<success>1</success>";
}
function retire_batch($r) {
function handle_retire_batch($r) {
list($user, $user_submit) = authenticate_user($r, null);
$batch_id = (int)($r->batch_id);
$batch = BoincBatch::lookup_id($batch_id);
if ($batch->user_id != $user->id) {
error("not owner");
}
$wus = BoincWorkunit::enum("batch=$batch_id");
$now = time();
foreach ($wus as $wu) {
$wu->update("assimilate_state=2, transition_time=$now");
}
$batch->update("state=".BATCH_STATE_RETIRED);
retire_batch($batch);
echo "<success>1</success>";
}
@ -413,8 +405,8 @@ switch ($r->getName()) {
case 'query_batches': query_batches($r); break;
case 'query_batch': query_batch($r); break;
case 'query_job': query_job($r); break;
case 'abort_batch': abort_batch($r); break;
case 'retire_batch': retire_batch($r); break;
case 'abort_batch': handle_abort_batch($r); break;
case 'retire_batch': handle_retire_batch($r); break;
default: error("bad command");
}

View File

@ -149,7 +149,7 @@ function eligible_apps() {
if (!$user_submit) return null;
$a = array();
foreach($apps as $app) {
if ($user_submit->all_apps) {
if ($user_submit->submit_all) {
$a[] = $app;
} else {
if (BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id")) {

View File

@ -384,6 +384,7 @@ sys.path.insert(0, os.path.join('%s', 'py'))
[ 'appmgr', 'create_work', 'xadd', 'dbcheck_files_exist', 'run_in_ops',
'update_versions', 'parse_config', 'grep_logs', 'db_query',
'watch_tcp', 'sign_executable', 'dir_hier_move',
'manage_privileges',
'dir_hier_path', 'boinc_submit', 'demo_submit', 'demo_query' ])
map(lambda (s): install(srcdir('lib',s), dir('bin',s)),
[ 'crypt_prog' ])

162
tools/manage_privileges Executable file
View File

@ -0,0 +1,162 @@
#!/usr/bin/env php
<?php
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2011 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// script for controlling "manage" privileges.
// See http://boinc.berkeley.edu/trac/wiki/MultiUser
// Run this from the project directory.
// usage:
//
// manage_privileges grant userid {appname|all}
// manage_privileges revoke userid {appname|all}
// manage_privileges list
//
// grant/revoke the "manage" privileges for the given app (or all apps).
error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('display_startup_errors', true);
function usage() {
die("usage:
manage_privileges grant userid {appname|all}
manage_privileges revoke userid {appname|all}
manage_privileges list
");
}
function show_user($user) {
echo "$user->name (ID $user->id)\n";
}
function show_managers() {
echo "Users with global manager privileges: \n";
$buss = BoincUserSubmit::enum("manage_all<>0");
if (!count($buss)) {
echo "none\n";
} else {
foreach ($buss as $bus) {
$user = BoincUser::lookup_id($bus->user_id);
show_user($user);
}
}
$apps = BoincApp::enum(null);
foreach ($apps as $app) {
echo "\nUsers with manager privileges for $app->name:\n";
$busas = BoincUserSubmitApp::enum("app_id=$app->id and manage<>0");
if (!count($busas)) {
echo "none\n";
} else {
foreach ($busas as $busa) {
$user = BoincUser::lookup_id($busa->user_id);
show_user($user);
}
}
}
}
if (!file_exists("config.xml")) {
die("run this script from the project directory\n");
}
chdir("html/inc");
require_once("boinc_db.inc");
require_once("submit_db.inc");
if ($argc < 2) usage();
if ($argv[1] == "list") {
show_managers();
exit;
}
if ($argc < 4) usage();
$user = BoincUser::lookup_id($argv[2]);
if (!$user) {
die("no such user: ".$argv[1]."\n");
}
if ($argv[1] === "grant") {
$grant = true;
} else if ($argv[1] === "revoke") {
$grant = false;
} else {
usage();
}
if ($argv[3] === "all") {
$bus = BoincUserSubmit::lookup_userid($user->id);
if ($bus) {
if ($grant) {
if ($bus->manage_all) {
die("User $user->id already has global manage access\n");
} else {
$bus->update("manage_all=1");
}
} else {
if ($bus->manage_all) {
$bus->update("manage_all=0");
} else {
die("User $user->id does not have global manage access\n");
}
}
} else {
if ($grant) {
BoincUserSubmit::insert("user_id=$user->id and manage_all=1");
} else {
die("User $user->id does not have global manage access\n");
}
}
} else {
$app = BoincApp::lookup_name($argv[3]);
if (!$app) die("no such app: ".$argv[2]."\n");
$busa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id");
if ($busa) {
if ($grant) {
if ($busa->manage) {
die("User $user->id already has manage access for $app->name\n");
} else {
$busa->update("manage=1");
}
} else {
if ($busa->manage) {
$busa->update("manage=0");
} else {
die("User $user->id does not have manage access for $app->name\n");
}
}
} else {
if ($grant) {
$bus = BoincUserSubmit::lookup(userid($user->id);
if (!$bus) {
BoincUserSubmit::insert("user_id=$user->id=1");
}
BoincUserSubmitApp::insert("user_id=$user->id and app_id=$app->id and manage=1");
} else {
die("User $user->id does not have manage access for $app->name\n");
}
}
}
echo "Done.\n";
?>