Skip to content
This repository was archived by the owner on Sep 19, 2022. It is now read-only.

Commit 9391931

Browse files
melangervyskocilpavel
authored andcommitted
Store detailed statistics(with some user identifier) for several days
1 parent acf9c79 commit 9391931

File tree

6 files changed

+130
-9
lines changed

6 files changed

+130
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file.
2121
#### Added
2222
- Added configuration file for ESLint
2323
- Module now supports running statistics as IDP/SP
24+
- Store detailed statistics(include some user identifier) for several days
2425

2526
#### Changed
2627
- Using of short array syntax (from array() to [])

config-templates/module_statisticsproxy.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,29 @@
6565
*/
6666
],
6767

68+
/*
69+
* For how many days should detailed statistics (per user) be kept.
70+
* @default 0
71+
*/
72+
'detailedDays' => 0,
73+
74+
/**
75+
* Which attribute should be used as user ID.
76+
* @default uid
77+
*/
78+
'userIdAttribute' => 'uid',
79+
6880
/*
6981
* Fill the table name for statistics
7082
*/
7183
'statisticsTableName' => 'statisticsTableName',
7284

85+
/*
86+
* Fill the table name for detailed statistics
87+
* @default
88+
*/
89+
'detailedStatisticsTableName' => 'statistics_detail',
90+
7391
/*
7492
* Fill the table name for identityProvidersMap
7593
*/

config-templates/tables.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ CREATE TABLE statistics (
1111
PRIMARY KEY (year, month, day, sourceIdp, service)
1212
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1313

14+
CREATE TABLE statistics_detail (
15+
year INT NOT NULL,
16+
month INT NOT NULL,
17+
day INT NOT NULL,
18+
sourceIdp VARCHAR(255) NOT NULL,
19+
service VARCHAR(255) NOT NULL,
20+
user VARCHAR(255) NOT NULL,
21+
count INT,
22+
INDEX (sourceIdp),
23+
INDEX (service),
24+
PRIMARY KEY (year, month, day, sourceIdp, service, user)
25+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
26+
1427
--Tables for mapping identifier to name
1528
CREATE TABLE identityProvidersMap(
1629
entityId VARCHAR(255) NOT NULL,

hooks/hook_cron.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/**
4+
* Hook to run a cron job.
5+
*
6+
* @param array &$croninfo Output
7+
* @return void
8+
*/
9+
function proxystatistics_hook_cron(&$croninfo)
10+
{
11+
if ($croninfo['tag'] !== 'daily') {
12+
\SimpleSAML\Logger::debug('cron [proxystatistics]: Skipping cron in cron tag ['.$croninfo['tag'].'] ');
13+
return;
14+
}
15+
16+
\SimpleSAML\Logger::info('cron [proxystatistics]: Running cron in cron tag ['.$croninfo['tag'].'] ');
17+
18+
try {
19+
$dbCmd = new \SimpleSAML\Module\proxystatistics\Auth\Process\DatabaseCommand();
20+
$dbCmd->deleteOldDetailedStatistics();
21+
} catch (\Exception $e) {
22+
$croninfo['summary'][] = 'Error during deleting old detailed statistics: '.$e->getMessage();
23+
}
24+
}

lib/Auth/Process/DatabaseCommand.php

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,49 @@ class DatabaseCommand
1414
private $databaseConnector;
1515
private $conn;
1616
private $statisticsTableName;
17+
private $detailedStatisticsTableName;
1718
private $identityProvidersMapTableName;
1819
private $serviceProvidersMapTableName;
1920

2021
public function __construct()
2122
{
2223
$this->databaseConnector = new DatabaseConnector();
2324
$this->conn = $this->databaseConnector->getConnection();
24-
assert($this->conn != null);
25+
assert($this->conn !== null);
2526
$this->statisticsTableName = $this->databaseConnector->getStatisticsTableName();
27+
$this->detailedStatisticsTableName = $this->databaseConnector->getDetailedStatisticsTableName();
2628
$this->identityProvidersMapTableName = $this->databaseConnector->getIdentityProvidersMapTableName();
2729
$this->serviceProvidersMapTableName = $this->databaseConnector->getServiceProvidersMapTableName();
2830
}
2931

32+
private function writeLogin($year, $month, $day, $sourceIdp, $service, $user = null)
33+
{
34+
$params = [
35+
'year' => $year,
36+
'month' => $month,
37+
'day' => $day,
38+
'sourceIdp' => $sourceIdp,
39+
'service' => $service,
40+
'count' => 1,
41+
];
42+
$table = $this->statisticsTableName;
43+
if ($user && $this->databaseConnector->getDetailedDays() > 0) {
44+
// write also into aggregated statistics
45+
self::writeLogin($year, $month, $day, $sourceIdp, $service);
46+
$params['user'] = $user;
47+
$table = $this->detailedStatisticsTableName;
48+
}
49+
$fields = array_keys($params);
50+
$placeholders = array_map(function ($field) {
51+
return ':' . $field;
52+
53+
}, $fields);
54+
$query = "INSERT INTO " . $table . " (" . implode(', ', $fields) . ")" .
55+
" VALUES (" . implode(', ', $placeholders) . ") ON DUPLICATE KEY UPDATE count = count + 1";
56+
57+
return $this->conn->write($query, $params);
58+
}
59+
3060
public function insertLogin(&$request, &$date)
3161
{
3262
if (!in_array($this->databaseConnector->getMode(), ['PROXY', 'IDP', 'SP'])) {
@@ -59,11 +89,9 @@ public function insertLogin(&$request, &$date)
5989
" is empty and login log wasn't inserted into the database."
6090
);
6191
} else {
62-
if ($this->conn->write(
63-
"INSERT INTO " . $this->statisticsTableName . "(year, month, day, sourceIdp, service, count)" .
64-
" VALUES (:year, :month, :day, :idp, :sp, '1') ON DUPLICATE KEY UPDATE count = count + 1",
65-
['year'=>$year, 'month'=>$month, 'day'=>$day, 'idp'=>$idpEntityID, 'sp'=>$spEntityId]
66-
) === false) {
92+
$idAttribute = $this->databaseConnector->getUserIdAttribute();
93+
$userId = isset($request['Attributes'][$idAttribute]) ? $request['Attributes'][$idAttribute][0] : null;
94+
if ($this->writeLogin($year, $month, $day, $idpEntityID, $spEntityId, $userId) === false) {
6795
Logger::error("The login log wasn't inserted into table: " . $this->statisticsTableName . ".");
6896
}
6997

@@ -197,17 +225,30 @@ public function getLoginCountPerIdp($days)
197225
return $this->conn->read($query, $params)->fetchAll(PDO::FETCH_NUM);
198226
}
199227

200-
private static function addDaysRange($days, &$query, &$params)
228+
private static function addDaysRange($days, &$query, &$params, $not = false)
201229
{
202230
if ($days != 0) { // 0 = all time
203231
if (stripos($query, "WHERE") === false) {
204232
$query .= "WHERE";
205233
} else {
206234
$query .= "AND";
207235
}
208-
$query .= " CONCAT(year,'-',LPAD(month,2,'00'),'-',LPAD(day,2,'00')) " .
209-
"BETWEEN CURDATE() - INTERVAL :days DAY AND CURDATE() ";
236+
$query .= " CONCAT(year,'-',LPAD(month,2,'00'),'-',LPAD(day,2,'00')) ";
237+
if ($not) {
238+
$query .= "NOT ";
239+
}
240+
$query .= "BETWEEN CURDATE() - INTERVAL :days DAY AND CURDATE() ";
210241
$params['days'] = $days;
211242
}
212243
}
244+
245+
public function deleteOldDetailedStatistics()
246+
{
247+
if ($this->databaseConnector->getDetailedDays() > 0) {
248+
$query = "DELETE FROM " . $this->detailedStatisticsTableName . " ";
249+
$params = [];
250+
self::addDaysRange($this->databaseConnector->getDetailedDays(), $query, $params, true);
251+
return $this->conn->write($query, $params);
252+
}
253+
}
213254
}

lib/Auth/Process/DatabaseConnector.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,16 @@
1414
class DatabaseConnector
1515
{
1616
private $statisticsTableName;
17+
private $detailedStatisticsTableName;
1718
private $identityProvidersMapTableName;
1819
private $serviceProvidersMapTableName;
1920
private $mode;
2021
private $idpEntityId;
2122
private $idpName;
2223
private $spEntityId;
2324
private $spName;
25+
private $detailedDays;
26+
private $userIdAttribute;
2427
private $conn = null;
2528

2629
const CONFIG_FILE_NAME = 'module_statisticsproxy.php';
@@ -35,6 +38,7 @@ class DatabaseConnector
3538
/** @deprecated */
3639
const DATABASE = 'databaseName';
3740
const STATS_TABLE_NAME = 'statisticsTableName';
41+
const DETAILED_STATS_TABLE_NAME = 'detailedStatisticsTableName';
3842
const IDP_MAP_TABLE_NAME = 'identityProvidersMapTableName';
3943
const SP_MAP_TABLE_NAME = 'serviceProvidersMapTableName';
4044
/** @deprecated */
@@ -53,6 +57,8 @@ class DatabaseConnector
5357
const IDP_NAME = 'idpName';
5458
const SP_ENTITY_ID = 'spEntityId';
5559
const SP_NAME = 'spName';
60+
const DETAILED_DAYS = 'detailedDays';
61+
const USER_ID_ATTRIBUTE = 'userIdAttribute';
5662

5763
public function __construct()
5864
{
@@ -87,13 +93,16 @@ public function __construct()
8793
$this->storeConfig = Configuration::loadFromArray($this->storeConfig);
8894

8995
$this->statisticsTableName = $conf->getString(self::STATS_TABLE_NAME);
96+
$this->detailedStatisticsTableName = $conf->getString(self::DETAILED_STATS_TABLE_NAME, 'statistics_detail');
9097
$this->identityProvidersMapTableName = $conf->getString(self::IDP_MAP_TABLE_NAME);
9198
$this->serviceProvidersMapTableName = $conf->getString(self::SP_MAP_TABLE_NAME);
9299
$this->mode = $conf->getString(self::MODE, 'PROXY');
93100
$this->idpEntityId = $conf->getString(self::IDP_ENTITY_ID, '');
94101
$this->idpName = $conf->getString(self::IDP_NAME, '');
95102
$this->spEntityId = $conf->getString(self::SP_ENTITY_ID, '');
96103
$this->spName = $conf->getString(self::SP_NAME, '');
104+
$this->detailedDays = $conf->getInteger(self::DETAILED_DAYS, 0);
105+
$this->userIdAttribute = $conf->getString(self::USER_ID_ATTRIBUTE, 'uid');
97106
}
98107

99108
public function getConnection()
@@ -106,6 +115,11 @@ public function getStatisticsTableName()
106115
return $this->statisticsTableName;
107116
}
108117

118+
public function getDetailedStatisticsTableName()
119+
{
120+
return $this->detailedStatisticsTableName;
121+
}
122+
109123
public function getIdentityProvidersMapTableName()
110124
{
111125
return $this->identityProvidersMapTableName;
@@ -140,4 +154,14 @@ public function getSpName()
140154
{
141155
return $this->spName;
142156
}
157+
158+
public function getDetailedDays()
159+
{
160+
return $this->detailedDays;
161+
}
162+
163+
public function getUserIdAttribute()
164+
{
165+
return $this->userIdAttribute;
166+
}
143167
}

0 commit comments

Comments
 (0)