Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Support for capabilities module #52

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
14 changes: 14 additions & 0 deletions group_capabilities.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

$capabilities['group'] = [
'group_create' => 'create groups',
'group_edit' => 'edit group info',
'group_delete' => 'delete groups',
'group_create_user' => 'create new users inside groups',
'group_add_member_auth' => 'add users to groups (with password)',
'group_add_member_no_auth' => 'add users to groups (without password)',
'group_add_member_invite' => 'invite users to join groups',
'group_delete_user' => 'delete users',
'group_edit_user' => 'edit user info',
'group_impersonate' => 'can impersonate other users',
];
16 changes: 16 additions & 0 deletions group_controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
// no direct access
defined('EMONCMS_EXEC') or die('Restricted access');


// Make sure we have our capability check function
if (is_file("Modules/user_capabilities/user_capabilities.php")) {
require_once "Modules/user_capabilities/user_capabilities.php";
} else {
function user_has_capability($args) {
return true;
}
}

function group_controller() {
global $session, $route, $mysqli, $redis, $user, $feed_settings, $log;

Expand Down Expand Up @@ -150,6 +160,12 @@ function group_controller() {
// SPECIAL USER SWITCHING FUNCTIONS
// --------------------------------------------------------------------------
if ($route->action == 'setuser') {
// Check capability
if (!user_has_capability('group_impersonate')) {
http_response_code(403);
return _("You don't have permission to do that.");
}

$route->format = "text";
$groupid = (int) get('groupid');
$userid = (int) get('userid');
Expand Down
120 changes: 94 additions & 26 deletions group_model.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,16 @@
// no direct access
defined('EMONCMS_EXEC') or die('Restricted access');

class Group {
// Make sure we have our capability check function
if (is_file("Modules/user_capabilities/user_capabilities.php")) {
require_once "Modules/user_capabilities/user_capabilities.php";
} else {
function user_has_capability($args) {
return true;
}
}

class Group {
private $mysqli;
private $user;
private $feed;
Expand All @@ -38,8 +46,22 @@ public function __construct($mysqli, $redis, $user, $feed, $input, $task = null)
$this->task = $task;
}

private function no_permission() {
http_response_code(403);

return [
'success' => false,
'message' => _("You don't have permission to do that")
];
}

// Create group, add creator user as administrator
public function create($userid, $name, $description, $organization, $area, $visibility, $access) {
// Check capability
if (!user_has_capability('group_create')) {
return $this->no_permission();
}

// Input sanitisation
$userid = (int) $userid;
$name = preg_replace('/[^\w\s-:]/', '', $name);
Expand All @@ -49,31 +71,35 @@ public function create($userid, $name, $description, $organization, $area, $visi
$visibility = $visibility == 'public' ? 'public' : 'private';
$access = $access == 'open' ? 'open' : 'closed';


if ($this->exists_name($name)) {
$this->log->warn("Cannot create group, already exists");
return array('success' => false, 'message' => _("Cannot create group, already exists"));
$this->log->warn("Cannot create group as a group with that name already exists");
return array('success' => false, 'message' => _("Cannot create group as a group with that name already exists"));
}

$stmt = $this->mysqli->prepare("INSERT INTO groups (name,description, organization, area, visibility, access) VALUES (?,?,?,?,?,?)");
$stmt = $this->mysqli->prepare("INSERT INTO groups (name, description, organization, area, visibility, access) VALUES (?,?,?,?,?,?)");
$stmt->bind_param("ssssss", $name, $description, $organization, $area, $visibility, $access);
if (!$stmt->execute()) {
$this->log->error("Error creating group, problem with sql statement");
return array('success' => false, 'message' => _("Error creating group"));
return array('success' => false, 'message' => _("Couldn't create group"));
}
$groupid = $this->mysqli->insert_id;

if (!$this->add_user($groupid, $userid, 1)) {
$this->log->error("Error adding user to group " . $groupid);
return array('success' => false, 'message' => _("Error adding user to group"));
$this->log->error("Error adding user $userid to group $groupid");
return array('success' => false, 'message' => _("Group created, but couldn't add you to it"));
}

$this->log->info("Group $groupid added");
return array('success' => true, 'groupid' => $groupid, 'message' => _("Group $groupid added"));
return array('success' => true, 'groupid' => $groupid, 'message' => _("Group '$name' added"));
}

// Edit group
public function editgroup($admin_userid, $groupid, $name, $description, $organization, $area, $visibility, $access) {
// Check capability
if (!user_has_capability('group_edit')) {
return $this->no_permission();
}

// Input sanitisation
$groupid = (int) $groupid;
$admin_userid = (int) $admin_userid;
Expand All @@ -89,33 +115,40 @@ public function editgroup($admin_userid, $groupid, $name, $description, $organiz
$stmt->bind_param("ssssssi", $name, $description, $organization, $area, $visibility, $access, $groupid);
if (!$stmt->execute()) {
$this->log->error("Error editing group, problem with sql statement");
return array('success' => false, 'message' => _("Error editing group"));
return array('success' => false, 'message' => _("Error updating group"));
}
$this->log->info("Group edited");
return array('success' => true, 'message' => _("Group edited"));
return array('success' => true, 'message' => _("Group updated"));

}
else {

$this->log->warning("Error editing group, You are not administrator of the group - Session userid: " . $admin_userid);
return array('success' => false, 'message' => _("You are not administrator of the group"));
}
}

public function createuseraddtogroup($admin_userid, $groupid, $email, $username, $password, $role, $name) {
// Check capability
if (!user_has_capability('group_create_user')) {
return $this->no_permission();
}

// Input sanitisation
$admin_userid = (int) $admin_userid;
$groupid = (int) $groupid;
$role = (int) $role;
// email, username and password checked within $user model and $name

if (!$this->exists($groupid)) {
$this->log->warn("Group " . $groupid . " does not exist");
$this->log->warn("Group $groupid does not exist");
return array('success' => false, 'message' => _("Group does not exist"));
}

// 1. Check that user is a group administrator
if (!$this->is_group_admin($groupid, $admin_userid)) {
$this->log->warn("You haven't got enough permissions to add a member to this group - Session userid: " . $admin_userid);
return array('success' => false, 'message' => _("You haven't got enough permissions to add a member to this group"));
$this->log->warn("User $admin_userid called createuseraddtogroup without permission");
return array('success' => false, 'message' => _("You don't have permission to add someone to this group"));
}

// 2. Check username and password, return
Expand All @@ -131,18 +164,24 @@ public function createuseraddtogroup($admin_userid, $groupid, $email, $username,
$user_data->name = $name;
$result = $this->user->set($add_userid, $user_data);

// 3. Add user to group
// 3. Add user to group
if (!$this->add_user($groupid, $add_userid, $role, $admin_rights = 'full')) {
$this->log->error("Error adding user to group");
return array('success' => false, 'message' => _("Error adding user to group"));
return array('success' => false, 'message' => _("User created, but couldn't add to group"));
}

$this->log->info("User $add_userid:$username added to group " . $groupid);
return array('success' => true, 'message' => _("User $add_userid:$username added"), 'userid' => $add_userid);
return array('success' => true, 'message' => _("User '$username' created and added to group"), 'userid' => $add_userid);
}

// Add user to a group if admin user knows account username and password
public function add_user_auth($admin_userid, $groupid, $username, $password, $role) {
// Check capability
if (!user_has_capability('group_add_member_auth') &&
!user_has_capability('group_add_member_no_auth')) {
return $this->no_permission();
}

// Input sanitisation
$admin_userid = (int) $admin_userid;
$groupid = (int) $groupid;
Expand All @@ -160,15 +199,24 @@ public function add_user_auth($admin_userid, $groupid, $username, $password, $ro
return array('success' => false, 'message' => _("You haven't got enough permissions to add a member to this group"));
}

// 2. Check username and password, return
$result = $this->user->get_apikeys_from_login($username, $password);
if (!$result["success"]) {
$this->log->error("Error adding user to group, username and password don't match - Session userid: " . $admin_userid);
return $result;
// 2. Check username and password if required
// We only allow adding without a password if the capabilities module is loaded
if (class_exists('Capabilities') && user_has_capability('group_add_member_no_auth')) {
$add_userid = $this->user->get_id($username);
if (!$add_userid) {
$this->log->error("Error adding user to group: user $username doesn't exist");
return [ 'success' => false, 'message' => _("User doesn't exist") ];
}
} else {
$result = $this->user->get_apikeys_from_login($username, $password);
if (!$result["success"]) {
$this->log->error("Error adding user to group, username and password don't match - Session userid: " . $admin_userid);
return $result;
}
$add_userid = $result["userid"];
}
$add_userid = $result["userid"];

// 3. Add user to group
// 3. Add user to group
if (!$this->add_user($groupid, $add_userid, $role)) {
$this->log->error("Error adding user to group");
return array('success' => false, 'message' => _("Error adding user to group"));
Expand All @@ -180,12 +228,17 @@ public function add_user_auth($admin_userid, $groupid, $username, $password, $ro

// Send email invite to user to join a group
public function add_user_invite($userid, $groupid, $invite_userid) {
// Check capability
if (!user_has_capability('group_add_member_invite')) {
return $this->no_permission();
}

// Input sanitisation
$userid = (int) $userid;
$groupid = (int) $groupid;
}

// Return list of groups which $userid belongs and has right to list
// Return list of groups which $userid belongs and has right to list
public function grouplist($userid) {
// Input sanitisation
$userid = (int) $userid;
Expand Down Expand Up @@ -402,6 +455,11 @@ public function getuserinputs($session_userid, $groupid, $userid) {
}

public function delete($userid, $groupid) {
// Check capability
if (!user_has_capability('group_delete')) {
return $this->no_permission();
}

// Input sanitisation
$userid = (int) $userid;
$groupid = (int) $groupid;
Expand Down Expand Up @@ -462,6 +520,11 @@ public function remove_user($userid, $groupid, $userid_to_remove) {

// Remove user from database and group
public function full_remove_user($session_userid, $groupid, $userid_to_remove) {
// Check capability
if (!user_has_capability('group_delete_user')) {
return $this->no_permission();
}

// Input sanitisation
$session_userid = (int) $session_userid;
$groupid = (int) $groupid;
Expand Down Expand Up @@ -544,11 +607,16 @@ public function add_user($groupid, $userid, $role = 0, $admin_rights = 'full') {
$this->log->error('Cannot add user to group, error in query');
return false;
}
$this->log->info('User ' . $userid . ' added to group ' . '$groupid');
$this->log->info("User $userid added to group $groupid");
return true;
}

public function setuserinfo($session_userid, $groupid, $to_set_userid, $username, $name, $email, $bio, $timezone, $location, $role, $password, $tags) {
// Check capability
if (!user_has_capability('group_edit_user')) {
return $this->no_permission();
}

// Input sanitisation
$session_userid = (int) $session_userid;
$groupid = (int) $groupid;
Expand Down
46 changes: 40 additions & 6 deletions group_view.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,42 @@
<h3 style="padding-left:10px">Groups</h3>
<div id="grouplist"></div>

<div id="groupcreate"><i class="icon-plus"></i>New Group</div>
<?php if (user_has_capability('group_create')) { ?>
<div id="groupcreate"><i class="icon-plus"></i> New Group</div>
<?php } ?>
</div>

<div class="page-content" style="padding-top:15px">
<div style="padding-bottom:15px">
<button class="btn" id="sidebar-open" style="display:none"><i class="icon-list"></i></button>
<!--<div id="create-inputs-feeds" class="if-admin groupselected"><i class="icon-trash"></i>Update inputs/feeds</div>-->
<button id="deletegroup" class="btn if-admin groupselected"><i class="icon-trash"></i> Delete group</button>
<button id="editgroup" class="btn if-admin groupselected"><i class="icon-edit"></i> Edit Group</button>
<button id="createuseraddtogroup" class="btn if-admin groupselected"><i class="icon-plus"></i> Create User</button>
<button id="addmember" class="btn if-admin groupselected"><i class="icon-plus"></i> Add Member</button>

<?php if (user_has_capability('group_delete')) { ?>
<button id="deletegroup" class="btn if-admin groupselected">
<i class="icon-trash"></i> Delete group
</button>
<?php } ?>

<?php if (user_has_capability('group_edit')) { ?>
<button id="editgroup" class="btn if-admin groupselected">
<i class="icon-edit"></i> Edit Group
</button>
<?php } ?>

<?php if (user_has_capability('group_create_user')) { ?>
<button id="createuseraddtogroup" class="btn if-admin groupselected">
<i class="icon-plus"></i> Create User
</button>
<?php } ?>

<?php if (user_has_capability('group_add_member_invite') ||
user_has_capability('group_add_member_auth') ||
user_has_capability('group_add_member_no_auth')) { ?>
<button id="addmember" class="btn if-admin groupselected">
<i class="icon-plus"></i> Add Member
</button>
<?php } ?>

<div class="userstitle"><span id="groupname">Users</span></div>
<div id="groupdescription"></div>

Expand Down Expand Up @@ -132,10 +157,15 @@
<p>Username:<br>
<input id="group-addmember-username" type="text"></p>

<?php if (user_has_capability('group_add_member_auth') &&
!user_has_capability('group_add_member_no_auth')) { ?>

<p>Password:<br>
<input id="group-addmember-password" type="password">
<button class="generate-password btn" style="margin-bottom: 10px"><i class="icon-eye-open show-password"></i> Generate pasword</button></p>

<?php } ?>

<p>Role <i title="- Administrator: full access (create users, add member, create group feeds, dashboards graphs, etc)&#10;- Sub-administrator: view access to the list of members, write access to group graphs&#10;- Passive member: no access to group. The aim of the user is to be managed by the group administrator" class=" icon-question-sign"></i>:</p>
<select id="group-addmember-access">
<option value=1>Administrator</option>
Expand Down Expand Up @@ -444,6 +474,10 @@
var summary_for_search = [];
var task_support = <?php echo $task_support === false ? 0 : 1; ?> === 1 ? true : false;

var capability = {
can_impersonate: <?= json_encode(user_has_capability('group_impersonate')) ?>,
}

<?php if (isset($groups_email_subject) && isset($groups_email_body)) { ?>
var EMAIL_SUBJECT = <?= json_encode($groups_email_subject) ?>;
var EMAIL_BODY = <?= json_encode($groups_email_body) ?>;
Expand Down Expand Up @@ -620,7 +654,7 @@ function draw_userlist(groupid) {
out += "<div class='user-actions'>";
if (userlist[z].userid != my_userid) {
if (userlist[z].admin_rights == 'full') {
if (my_role == 1) {
if (my_role == 1 && capability.can_impersonate) {
out += "<button title='Log in as user'" +
" class='btn setuser if-admin'" +
" gid=" + selected_groupid +
Expand Down