Skip to content

Commit

Permalink
Merge branch 'local_user_managment' into local_auth_example
Browse files Browse the repository at this point in the history
  • Loading branch information
mettke committed May 4, 2019
2 parents caa65e4 + 34aa934 commit d62e061
Show file tree
Hide file tree
Showing 16 changed files with 360 additions and 56 deletions.
1 change: 1 addition & 0 deletions config/config-sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ password = password
database = ska-db

[ldap]
enabled = 0
; Address to connect to LDAP server
host = ldaps://ldap.example.com:636
; Use StartTLS for connection security (recommended if using ldap:// instead
Expand Down
10 changes: 6 additions & 4 deletions core.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@
require('ldap.php');
require('email.php');

$ldap_options = array();
$ldap_options[LDAP_OPT_PROTOCOL_VERSION] = 3;
$ldap_options[LDAP_OPT_REFERRALS] = !empty($config['ldap']['follow_referrals']);
$ldap = new LDAP($config['ldap']['host'], $config['ldap']['starttls'], $config['ldap']['bind_dn'], $config['ldap']['bind_password'], $ldap_options);
if ($config['ldap']['enabled'] == 1) {
$ldap_options = array();
$ldap_options[LDAP_OPT_PROTOCOL_VERSION] = 3;
$ldap_options[LDAP_OPT_REFERRALS] = !empty($config['ldap']['follow_referrals']);
$ldap = new LDAP($config['ldap']['host'], $config['ldap']['starttls'], $config['ldap']['bind_dn'], $config['ldap']['bind_password'], $ldap_options);
}
setup_database();

$relative_frontend_base_url = (string)parse_url($config['web']['baseurl'], PHP_URL_PATH);
Expand Down
159 changes: 159 additions & 0 deletions migrations/004.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php
$migration_name = 'Add local usermanagment';

function free_results($database) {
do {
if ($res = $database->store_result()) {
$res->free();
}
} while ($database->more_results() && $database->next_result());
}

$this->database->autocommit(FALSE);

$result = $this->database->query("
SELECT uid FROM user WHERE uid = 'keys-sync'
");
if ($result) {
if($result->num_rows === 0) {
$result->close();
$result = $this->database->multi_query("
INSERT INTO entity SET type = 'user';
INSERT INTO user SET entity_id = (
SELECT LAST_INSERT_ID()
), uid = 'keys-sync', name = 'Synchronization script', email = '', auth_realm = 'local', admin = 1;
");
free_results($this->database);
} else {
$result->close();
$this->database->query("
UPDATE user SET auth_realm = 'local', active = 1 WHERE uid = 'keys-sync';
");
}
}


$this->database->multi_query("
CREATE TABLE `entity_event_2` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`entity_id` int(10) unsigned NOT NULL,
`actor_id` int(10) unsigned,
`date` datetime NOT NULL,
`details` mediumtext NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_entity_event_entity_id` (`entity_id`),
KEY `FK_entity_event_actor_id` (`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT entity_event_2 SELECT * FROM entity_event;
DROP TABLE entity_event;
RENAME TABLE entity_event_2 TO entity_event;
ALTER TABLE `entity_event`
ADD CONSTRAINT `FK_entity_event_actor_id` FOREIGN KEY (`actor_id`) REFERENCES `entity` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `FK_entity_event_entity_id` FOREIGN KEY (`entity_id`) REFERENCES `entity` (`id`) ON DELETE CASCADE;
");
free_results($this->database);


$this->database->multi_query("
CREATE TABLE `group_event_2` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`group` int(10) unsigned NOT NULL,
`entity_id` int(10) unsigned,
`date` datetime NOT NULL,
`details` mediumtext NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_group_event_group` (`group`),
KEY `FK_group_event_entity` (`entity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;
INSERT group_event_2 SELECT * FROM group_event;
DROP TABLE group_event;
RENAME TABLE group_event_2 TO group_event;
ALTER TABLE `group_event`
ADD CONSTRAINT `FK_group_event_entity` FOREIGN KEY (`entity_id`) REFERENCES `entity` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `FK_group_event_group` FOREIGN KEY (`group`) REFERENCES `group` (`entity_id`) ON DELETE CASCADE;
");
free_results($this->database);


$this->database->multi_query("
CREATE TABLE `group_member_2` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`group` int(10) unsigned NOT NULL,
`entity_id` int(10) unsigned NOT NULL,
`add_date` datetime NOT NULL,
`added_by` int(10) unsigned,
PRIMARY KEY (`id`),
UNIQUE KEY `group_entity_id` (`group`, `entity_id`),
KEY `FK_group_member_entity` (`entity_id`),
KEY `FK_group_member_entity_2` (`added_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;
INSERT group_member_2 SELECT * FROM group_member;
DROP TABLE group_member;
RENAME TABLE group_member_2 TO group_member;
ALTER TABLE `group_member`
ADD CONSTRAINT `FK_group_member_entity` FOREIGN KEY (`entity_id`) REFERENCES `entity` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `FK_group_member_entity_2` FOREIGN KEY (`added_by`) REFERENCES `entity` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `FK_group_member_group` FOREIGN KEY (`group`) REFERENCES `group` (`entity_id`) ON DELETE CASCADE
");
free_results($this->database);


$this->database->multi_query("
CREATE TABLE `server_event_2` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`server_id` int(10) unsigned NOT NULL,
`actor_id` int(10) unsigned,
`date` datetime NOT NULL,
`details` mediumtext NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_server_log_server` (`server_id`),
KEY `FK_server_event_actor_id` (`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT server_event_2 SELECT * FROM server_event;
DROP TABLE server_event;
RENAME TABLE server_event_2 TO server_event;
ALTER TABLE `server_event`
ADD CONSTRAINT `FK_server_event_actor_id` FOREIGN KEY (`actor_id`) REFERENCES `entity` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `FK_server_log_server` FOREIGN KEY (`server_id`) REFERENCES `server` (`id`) ON DELETE CASCADE;
");
free_results($this->database);


$this->database->multi_query("
CREATE TABLE `server_note_2` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`server_id` int(10) unsigned NOT NULL,
`entity_id` int(10) unsigned,
`date` datetime NOT NULL,
`note` mediumtext NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_server_note_server` (`server_id`),
KEY `FK_server_note_user` (`entity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT server_note_2 SELECT * FROM server_note;
DROP TABLE server_note;
RENAME TABLE server_note_2 TO server_note;
ALTER TABLE `server_note`
ADD CONSTRAINT `FK_server_note_entity` FOREIGN KEY (`entity_id`) REFERENCES `entity` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `FK_server_note_server` FOREIGN KEY (`server_id`) REFERENCES `server` (`id`) ON DELETE CASCADE
");
free_results($this->database);

$this->database->commit();

$this->database->autocommit(TRUE);
2 changes: 1 addition & 1 deletion model/migrationdirectory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class MigrationDirectory extends DBDirectory {
/**
* Increment this constant to activate a new migration from the migrations directory
*/
const LAST_MIGRATION = 3;
const LAST_MIGRATION = 4;

public function __construct() {
parent::__construct();
Expand Down
17 changes: 17 additions & 0 deletions model/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ public function update() {
}
}

/**
* Delete the given user.
*/
public function delete() {
if(is_null($this->entity_id)) throw new BadMethodCallException('User must be in directory before it can be removed');
$stmt = $this->database->prepare("DELETE FROM entity WHERE id = ?");
$stmt->bind_param('d', $this->entity_id);
$stmt->execute();
$stmt->close();
$stmt = $this->database->prepare("DELETE FROM user WHERE entity_id = ?");
$stmt->bind_param('d', $this->entity_id);
$stmt->execute();
$stmt->close();

$this->sync_remote_access();
}

/**
* Magic getter method - if superior field requested, return User object of user's superior
* @param string $field to retrieve
Expand Down
41 changes: 29 additions & 12 deletions model/userdirectory.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,22 @@ public function add_user(User $user) {
$user_active = $user->active;
$user_admin = $user->admin;
$user_email = $user->email;
$stmt = $this->database->prepare("INSERT INTO entity SET type = 'user'");
$stmt->execute();
$user->entity_id = $stmt->insert_id;
$stmt = $this->database->prepare("INSERT INTO user SET entity_id = ?, uid = ?, name = ?, email = ?, active = ?, admin = ?");
$stmt->bind_param('dsssdd', $user->entity_id, $user_id, $user_name, $user_email, $user_active, $user_admin);
$stmt->execute();
$stmt->close();
try {
$stmt = $this->database->prepare("INSERT INTO entity SET type = 'user'");
$stmt->execute();
$user->entity_id = $stmt->insert_id;
$stmt = $this->database->prepare("INSERT INTO user SET entity_id = ?, uid = ?, name = ?, email = ?, active = ?, admin = ?, auth_realm = ?");
$stmt->bind_param('dsssdds', $user->entity_id, $user_id, $user_name, $user_email, $user_active, $user_admin, $user->auth_realm);
$stmt->execute();
$stmt->close();
} catch(mysqli_sql_exception $e) {
if($e->getCode() == 1062) {
// Duplicate entry
throw new UserAlreadyExistsException("User {$user->uid} already exists");
} else {
throw $e;
}
}
}

/**
Expand Down Expand Up @@ -82,6 +91,8 @@ public function get_user_by_id($id) {
* @throws UserNotFoundException if no user with that uid exists
*/
public function get_user_by_uid($uid) {
global $config;
$ldap_enabled = $config['ldap']['enabled'];
if(isset($this->cache_uid[$uid])) {
return $this->cache_uid[$uid];
}
Expand All @@ -93,11 +104,16 @@ public function get_user_by_uid($uid) {
$user = new User($row['entity_id'], $row);
$this->cache_uid[$uid] = $user;
} else {
$user = new User;
$user->uid = $uid;
$this->cache_uid[$uid] = $user;
$user->get_details_from_ldap();
$this->add_user($user);
if ($ldap_enabled == 1) {
$user = new User;
$user->uid = $uid;
$this->cache_uid[$uid] = $user;
$user->auth_realm = 'LDAP';
$user->get_details_from_ldap();
$this->add_user($user);
} else {
throw new UserNotFoundException('User does not exist.');
}
}
$stmt->close();
return $user;
Expand Down Expand Up @@ -148,3 +164,4 @@ public function list_users($include = array(), $filter = array()) {
}

class UserNotFoundException extends Exception {}
class UserAlreadyExistsException extends Exception {}
21 changes: 14 additions & 7 deletions requesthandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,32 @@
ob_start();
set_exception_handler('exception_handler');

if(isset($_SERVER['PHP_AUTH_USER'])) {
$active_user = $user_dir->get_user_by_uid($_SERVER['PHP_AUTH_USER']);
} else {
throw new Exception("Not logged in.");
}

// Work out where we are on the server
$base_path = dirname(__FILE__);
$base_url = dirname($_SERVER['SCRIPT_NAME']);
$request_url = $_SERVER['REQUEST_URI'];
$relative_request_url = preg_replace('/^'.preg_quote($base_url, '/').'/', '/', $request_url);
$absolute_request_url = 'http'.(isset($_SERVER['HTTPS']) ? 's' : '').'://'.$_SERVER['HTTP_HOST'].$request_url;

if(isset($_SERVER['PHP_AUTH_USER'])) {
try {
$active_user = $user_dir->get_user_by_uid($_SERVER['PHP_AUTH_USER']);
} catch(UserNotFoundException $ex) {
require('views/error403.php');
die;
}
} else {
throw new Exception("Not logged in.");
}

if(empty($config['web']['enabled'])) {
require('views/error503.php');
die;
}

if(!$active_user->active) {
require('views/error403.php');
die;
}

if(!empty($_POST)) {
Expand All @@ -62,10 +68,11 @@
if(isset($router->view)) {
$view = path_join($base_path, 'views', $router->view.'.php');
if(file_exists($view)) {
if($active_user->auth_realm == 'LDAP' || $router->public) {
if($active_user->auth_realm == 'LDAP' || $active_user->auth_realm == 'local' || $router->public) {
require($view);
} else {
require('views/error403.php');
die;
}
} else {
throw new Exception("View file $view missing.");
Expand Down
22 changes: 14 additions & 8 deletions scripts/ldap_update.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,28 @@
$active_user->uid = 'keys-sync';
$active_user->name = 'Synchronization script';
$active_user->email = '';
$active_user->auth_realm = 'local';
$active_user->active = 1;
$active_user->admin = 1;
$active_user->developer = 0;
$user_dir->add_user($active_user);
}

try {
$sysgrp = $group_dir->get_group_by_name($config['ldap']['admin_group_cn']);
} catch(GroupNotFoundException $e) {
$sysgrp = new Group;
$sysgrp->name = $config['ldap']['admin_group_cn'];
$sysgrp->system = 1;
$group_dir->add_group($sysgrp);
$ldap_enabled = $config['ldap']['enabled'];

if($ldap_enabled == 1) {
try {
$sysgrp = $group_dir->get_group_by_name($config['ldap']['admin_group_cn']);
} catch(GroupNotFoundException $e) {
$sysgrp = new Group;
$sysgrp->name = $config['ldap']['admin_group_cn'];
$sysgrp->system = 1;
$group_dir->add_group($sysgrp);
}
}

foreach($users as $user) {
if($user->auth_realm == 'LDAP') {
if($user->auth_realm == 'LDAP' && $ldap_enabled == 1) {
$active = $user->active;
try {
$user->get_details_from_ldap();
Expand Down
1 change: 1 addition & 0 deletions scripts/sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
$active_user->uid = 'keys-sync';
$active_user->name = 'Synchronization script';
$active_user->email = '';
$active_user->auth_realm = 'local';
$active_user->active = 1;
$active_user->admin = 1;
$active_user->developer = 0;
Expand Down
4 changes: 4 additions & 0 deletions templates/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ function show_event($event) {
<a href="<?php outurl('/groups/'.urlencode($event->group->name))?>" class="group"><?php out($event->group->name) ?></a>
<?php } ?>
</td>
<?php if(is_null($event->actor->uid)) { ?>
<td>removed</td>
<?php } else { ?>
<td><a href="<?php outurl('/users/'.urlencode($event->actor->uid))?>" class="user"><?php out($event->actor->uid) ?></a></td>
<?php } ?>
<td><?php out($details, ESC_NONE) ?></td>
<td class="nowrap"><?php out($event->date) ?></td>
</tr>
Expand Down
Loading

0 comments on commit d62e061

Please sign in to comment.