|
@@ -1,6 +1,8 @@
|
1
|
1
|
<?php
|
2
|
2
|
//var_dump($_SERVER['REQUEST_METHOD'],$_SERVER['PATH_INFO']); die();
|
3
|
3
|
|
|
4
|
+$configuration = include('config.php');
|
|
5
|
+
|
4
|
6
|
interface DatabaseInterface {
|
5
|
7
|
public function getSql($name);
|
6
|
8
|
public function connect($hostname,$username,$password,$database,$port,$socket,$charset);
|
|
@@ -764,10 +766,51 @@ class PHP_CRUD_API {
|
764
|
766
|
protected $db;
|
765
|
767
|
protected $settings;
|
766
|
768
|
|
|
769
|
+ protected function getVerifiedClaims($token,$time,$leeway,$ttl,$algorithm,$secret) {
|
|
770
|
+ $algorithms = array('HS256'=>'sha256','HS384'=>'sha384','HS512'=>'sha512');
|
|
771
|
+ if (!isset($algorithms[$algorithm])) return false;
|
|
772
|
+ $hmac = $algorithms[$algorithm];
|
|
773
|
+ $token = explode('.',$token);
|
|
774
|
+ if (count($token)<3) return false;
|
|
775
|
+ $header = json_decode(base64_decode(strtr($token[0],'-_','+/')),true);
|
|
776
|
+ if (!$secret) return false;
|
|
777
|
+ if ($header['typ']!='JWT') return false;
|
|
778
|
+ if ($header['alg']!=$algorithm) return false;
|
|
779
|
+ $signature = bin2hex(base64_decode(strtr($token[2],'-_','+/')));
|
|
780
|
+ if ($signature!=hash_hmac($hmac,"$token[0].$token[1]",$secret)) return false;
|
|
781
|
+ $claims = json_decode(base64_decode(strtr($token[1],'-_','+/')),true);
|
|
782
|
+ if (!$claims) return false;
|
|
783
|
+ if (isset($claims['nbf']) && $time+$leeway<$claims['nbf']) return false;
|
|
784
|
+ if (isset($claims['iat']) && $time+$leeway<$claims['iat']) return false;
|
|
785
|
+ if (isset($claims['exp']) && $time-$leeway>$claims['exp']) return false;
|
|
786
|
+ if (isset($claims['iat']) && !isset($claims['exp'])) {
|
|
787
|
+ if ($time-$leeway>$claims['iat']+$ttl) return false;
|
|
788
|
+ }
|
|
789
|
+ return $claims;
|
|
790
|
+ }
|
|
791
|
+
|
|
792
|
+ protected function generateToken($claims,$time,$ttl,$algorithm,$secret) {
|
|
793
|
+ $algorithms = array('HS256'=>'sha256','HS384'=>'sha384','HS512'=>'sha512');
|
|
794
|
+ $header = array();
|
|
795
|
+ $header['typ']='JWT';
|
|
796
|
+ $header['alg']=$algorithm;
|
|
797
|
+ $token = array();
|
|
798
|
+ $token[0] = rtrim(strtr(base64_encode(json_encode((object)$header)),'+/','-_'),'=');
|
|
799
|
+ $claims['iat'] = $time;
|
|
800
|
+ $claims['exp'] = $time + $ttl;
|
|
801
|
+ $token[1] = rtrim(strtr(base64_encode(json_encode((object)$claims)),'+/','-_'),'=');
|
|
802
|
+ if (!isset($algorithms[$algorithm])) return false;
|
|
803
|
+ $hmac = $algorithms[$algorithm];
|
|
804
|
+ $signature = hash_hmac($hmac,"$token[0].$token[1]",$secret,true);
|
|
805
|
+ $token[2] = rtrim(strtr(base64_encode($signature),'+/','-_'),'=');
|
|
806
|
+ return implode('.',$token);
|
|
807
|
+ }
|
|
808
|
+
|
767
|
809
|
protected function mapMethodToAction($method,$key) {
|
768
|
810
|
switch ($method) {
|
769
|
811
|
case 'OPTIONS': return 'headers';
|
770
|
|
- case 'GET': return $key?'read':'list';
|
|
812
|
+ case 'GET': return 'read';
|
|
813
|
+ //case 'GET': return $key?'read':'list';
|
771
|
814
|
case 'PUT': return 'update';
|
772
|
815
|
case 'POST': return 'create';
|
773
|
816
|
case 'DELETE': return 'delete';
|
|
@@ -1227,10 +1270,64 @@ class PHP_CRUD_API {
|
1227
|
1270
|
}
|
1228
|
1271
|
}
|
1229
|
1272
|
|
|
1273
|
+ protected function setCookie($configAuth) {
|
|
1274
|
+ $user = "token";
|
|
1275
|
+ $claims = array(
|
|
1276
|
+ 'sub' => $configAuth["sub"],
|
|
1277
|
+ 'name' => $user,
|
|
1278
|
+ 'admin' => $configAuth["admin"]
|
|
1279
|
+ );
|
|
1280
|
+
|
|
1281
|
+ if (!isset($_COOKIE[$user])) {
|
|
1282
|
+ $this->settings["authenticated"] = true;
|
|
1283
|
+ $cookie_value = $this->generateToken($claims,
|
|
1284
|
+ $configAuth["time"],$configAuth["ttl"],
|
|
1285
|
+ $configAuth["algorithm"],$configAuth["secret"]);
|
|
1286
|
+
|
|
1287
|
+ $_COOKIE[$user] = $cookie_value;
|
|
1288
|
+ setcookie($user, $cookie_value, time() +
|
|
1289
|
+ $configAuth["ttl"], '/');
|
|
1290
|
+ } else {
|
|
1291
|
+ setcookie($user, $_COOKIE[$user], time() +
|
|
1292
|
+ $configAuth["ttl"], '/');
|
|
1293
|
+ }
|
|
1294
|
+ }
|
|
1295
|
+
|
|
1296
|
+ protected function checkPassword($configAuth, $username, $password) {
|
|
1297
|
+ if ($configAuth['enabled']) {
|
|
1298
|
+ foreach($configAuth['users'] as $user=>$pass) {
|
|
1299
|
+ if ($user == $username && $pass == $password) {
|
|
1300
|
+ return true;
|
|
1301
|
+ }
|
|
1302
|
+ }
|
|
1303
|
+
|
|
1304
|
+ return false;
|
|
1305
|
+ }
|
|
1306
|
+
|
|
1307
|
+ return true;
|
|
1308
|
+ }
|
|
1309
|
+
|
1230
|
1310
|
protected function getParameters($settings) {
|
1231
|
1311
|
extract($settings);
|
1232
|
1312
|
|
|
1313
|
+ if (!isset($configuration)) {
|
|
1314
|
+ $configuration = include('config.php');
|
|
1315
|
+ }
|
|
1316
|
+
|
1233
|
1317
|
$table = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_');
|
|
1318
|
+ $isGetToken = false;
|
|
1319
|
+
|
|
1320
|
+ if ($configuration["authentication"]["enabled"] && $table == "getToken") {
|
|
1321
|
+ $isGetToken = true;
|
|
1322
|
+ $configAuth = $configuration["authentication"];
|
|
1323
|
+ $passedUsername = $this->parseGetParameter($get, 'username', 'a-zA-Z0-9\-_,');
|
|
1324
|
+ $passedPassword = $this->parseGetParameter($get, 'password', 'a-zA-Z0-9\-_,');
|
|
1325
|
+
|
|
1326
|
+ if ($this->checkPassword($configAuth, $passedUsername,
|
|
1327
|
+ $passedPassword)) {
|
|
1328
|
+ $this->setCookie($configAuth);
|
|
1329
|
+ }
|
|
1330
|
+ }
|
1234
|
1331
|
$key = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_'); // auto-increment or uuid
|
1235
|
1332
|
$action = $this->mapMethodToAction($method,$key);
|
1236
|
1333
|
$include = $this->parseGetParameter($get, 'include', 'a-zA-Z0-9\-_,');
|
|
@@ -1242,37 +1339,41 @@ class PHP_CRUD_API {
|
1242
|
1339
|
$order = $this->parseGetParameter($get, 'order', 'a-zA-Z0-9\-_,');
|
1243
|
1340
|
$transform = $this->parseGetParameter($get, 'transform', 't1');
|
1244
|
1341
|
|
1245
|
|
- $tables = $this->processTableAndIncludeParameters($database,$table,$include,$action);
|
1246
|
|
- $key = $this->processKeyParameter($key,$tables,$database);
|
1247
|
|
- $filters = $this->processFiltersParameter($tables,$satisfy,$filters);
|
1248
|
|
- $page = $this->processPageParameter($page);
|
1249
|
|
- $order = $this->processOrderParameter($order);
|
1250
|
|
-
|
1251
|
|
- // reflection
|
1252
|
|
- list($tables,$collect,$select) = $this->findRelations($tables,$database,$auto_include);
|
1253
|
|
- $columns = $this->addRelationColumns($columns,$select);
|
1254
|
|
- $fields = $this->findFields($tables,$columns,$database);
|
1255
|
|
-
|
1256
|
|
- // permissions
|
1257
|
|
- if ($table_authorizer) $this->applyTableAuthorizer($table_authorizer,$action,$database,$tables);
|
1258
|
|
- if (!isset($tables[0])) $this->exitWith404('entity');
|
1259
|
|
- if ($record_filter) $this->applyRecordFilter($record_filter,$action,$database,$tables,$filters);
|
1260
|
|
- if ($tenancy_function) $this->applyTenancyFunction($tenancy_function,$action,$database,$fields,$filters);
|
1261
|
|
- if ($column_authorizer) $this->applyColumnAuthorizer($column_authorizer,$action,$database,$fields);
|
1262
|
|
-
|
1263
|
|
- if ($post) {
|
1264
|
|
- // input
|
1265
|
|
- $context = $this->retrieveInput($post);
|
1266
|
|
- $input = $this->filterInputByFields($context,$fields[$tables[0]]);
|
1267
|
|
-
|
1268
|
|
- if ($tenancy_function) $this->applyInputTenancy($tenancy_function,$action,$database,$tables[0],$input,$fields[$tables[0]]);
|
1269
|
|
- if ($input_sanitizer) $this->applyInputSanitizer($input_sanitizer,$action,$database,$tables[0],$input,$fields[$tables[0]]);
|
1270
|
|
- if ($input_validator) $this->applyInputValidator($input_validator,$action,$database,$tables[0],$input,$fields[$tables[0]],$context);
|
|
1342
|
+ if (!$isGetToken) {
|
|
1343
|
+ $tables = $this->processTableAndIncludeParameters($database,$table,$include,$action);
|
|
1344
|
+ $key = $this->processKeyParameter($key,$tables,$database);
|
|
1345
|
+ $filters = $this->processFiltersParameter($tables,$satisfy,$filters);
|
|
1346
|
+ $page = $this->processPageParameter($page);
|
|
1347
|
+ $order = $this->processOrderParameter($order);
|
|
1348
|
+
|
|
1349
|
+ // reflection
|
|
1350
|
+ list($tables,$collect,$select) = $this->findRelations($tables,$database,$auto_include);
|
|
1351
|
+ $columns = $this->addRelationColumns($columns,$select);
|
|
1352
|
+ $fields = $this->findFields($tables,$columns,$database);
|
|
1353
|
+
|
|
1354
|
+ // permissions
|
|
1355
|
+ if ($table_authorizer) $this->applyTableAuthorizer($table_authorizer,$action,$database,$tables);
|
|
1356
|
+ if (!isset($tables[0])) $this->exitWith404('entity');
|
|
1357
|
+ if ($record_filter) $this->applyRecordFilter($record_filter,$action,$database,$tables,$filters);
|
|
1358
|
+ if ($tenancy_function) $this->applyTenancyFunction($tenancy_function,$action,$database,$fields,$filters);
|
|
1359
|
+ if ($column_authorizer) $this->applyColumnAuthorizer($column_authorizer,$action,$database,$fields);
|
|
1360
|
+
|
|
1361
|
+ if ($post) {
|
|
1362
|
+ // input
|
|
1363
|
+ $context = $this->retrieveInput($post);
|
|
1364
|
+ $input = $this->filterInputByFields($context,$fields[$tables[0]]);
|
|
1365
|
+
|
|
1366
|
+ if ($tenancy_function) $this->applyInputTenancy($tenancy_function,$action,$database,$tables[0],$input,$fields[$tables[0]]);
|
|
1367
|
+ if ($input_sanitizer) $this->applyInputSanitizer($input_sanitizer,$action,$database,$tables[0],$input,$fields[$tables[0]]);
|
|
1368
|
+ if ($input_validator) $this->applyInputValidator($input_validator,$action,$database,$tables[0],$input,$fields[$tables[0]],$context);
|
|
1369
|
+
|
|
1370
|
+ $this->convertBinary($input,$fields[$tables[0]]);
|
|
1371
|
+ }
|
1271
|
1372
|
|
1272
|
|
- $this->convertBinary($input,$fields[$tables[0]]);
|
|
1373
|
+ return compact('action','database','tables','key','callback','page','filters','fields','order','transform','input','collect','select');
|
|
1374
|
+ } else {
|
|
1375
|
+ return array('token');
|
1273
|
1376
|
}
|
1274
|
|
-
|
1275
|
|
- return compact('action','database','tables','key','callback','page','filters','fields','order','transform','input','collect','select');
|
1276
|
1377
|
}
|
1277
|
1378
|
|
1278
|
1379
|
protected function addWhereFromFilters($filters,&$sql,&$params) {
|
|
@@ -1482,6 +1583,22 @@ class PHP_CRUD_API {
|
1482
|
1583
|
$this->endOutput($callback);
|
1483
|
1584
|
}
|
1484
|
1585
|
|
|
1586
|
+ protected function tokenCommand() {
|
|
1587
|
+ $callback = "";
|
|
1588
|
+ $this->startOutput($callback);
|
|
1589
|
+ $json = '{"token": "' .$_COOKIE["token"]. '"}';
|
|
1590
|
+ echo $json;
|
|
1591
|
+ $this->endOutput($callback);
|
|
1592
|
+ }
|
|
1593
|
+
|
|
1594
|
+ protected function invalidToken() {
|
|
1595
|
+ $callback = "";
|
|
1596
|
+ $this->startOutput($callback);
|
|
1597
|
+ $json = '{"error": "Your token is invalid or it has expired"}';
|
|
1598
|
+ echo $json;
|
|
1599
|
+ $this->endOutput($callback);
|
|
1600
|
+ }
|
|
1601
|
+
|
1485
|
1602
|
public function __construct($config) {
|
1486
|
1603
|
extract($config);
|
1487
|
1604
|
|
|
@@ -1619,7 +1736,7 @@ class PHP_CRUD_API {
|
1619
|
1736
|
$table_list = array($table['name']);
|
1620
|
1737
|
$table_fields = $this->findFields($table_list,false,$database);
|
1621
|
1738
|
$table_names = array_map(function($v){ return $v['name'];},$tables);
|
1622
|
|
-
|
|
1739
|
+
|
1623
|
1740
|
if ($extensions) {
|
1624
|
1741
|
$result = $this->db->query($this->db->getSql('reflect_belongs_to'),array($table_list[0],$table_names,$database,$database));
|
1625
|
1742
|
while ($row = $this->db->fetchRow($result)) {
|
|
@@ -1634,7 +1751,7 @@ class PHP_CRUD_API {
|
1634
|
1751
|
$table_fields[$table['name']][$primaryKey]->primaryKey = true;
|
1635
|
1752
|
}
|
1636
|
1753
|
}
|
1637
|
|
-
|
|
1754
|
+
|
1638
|
1755
|
foreach (array('root_actions','id_actions') as $path) {
|
1639
|
1756
|
foreach ($table[$path] as $i=>$action) {
|
1640
|
1757
|
$table_list = array($table['name']);
|
|
@@ -1912,17 +2029,43 @@ class PHP_CRUD_API {
|
1912
|
2029
|
$this->swagger($this->settings);
|
1913
|
2030
|
} else {
|
1914
|
2031
|
$parameters = $this->getParameters($this->settings);
|
1915
|
|
- switch($parameters['action']){
|
1916
|
|
- case 'list': $this->listCommand($parameters); break;
|
1917
|
|
- case 'read': $this->readCommand($parameters); break;
|
1918
|
|
- case 'create': $this->createCommand($parameters); break;
|
1919
|
|
- case 'update': $this->updateCommand($parameters); break;
|
1920
|
|
- case 'delete': $this->deleteCommand($parameters); break;
|
1921
|
|
- case 'headers': $this->headersCommand($parameters); break;
|
|
2032
|
+
|
|
2033
|
+ if(isset($parameters[0]) && $parameters[0] == 'token') {
|
|
2034
|
+ $this->tokenCommand();
|
|
2035
|
+ } else {
|
|
2036
|
+ if (!isset($configuration)) {
|
|
2037
|
+ $configuration = include('config.php');
|
|
2038
|
+ }
|
|
2039
|
+
|
|
2040
|
+ if ($parameters['action'] == 'list') {
|
|
2041
|
+ $this->listCommand($parameters);
|
|
2042
|
+ } else if ($parameters['action'] == 'read') {
|
|
2043
|
+ $this->readCommand($parameters);
|
|
2044
|
+ } else if($configuration['authentication']['enabled']) {
|
|
2045
|
+ if (isset($_COOKIE["token"]) &&
|
|
2046
|
+ ($_COOKIE["token"] == $this->settings["get"]["token"])) {
|
|
2047
|
+ $this->setCookie($configuration["authentication"]);
|
|
2048
|
+
|
|
2049
|
+ switch($parameters['action']) {
|
|
2050
|
+ case 'create': $this->createCommand($parameters); break;
|
|
2051
|
+ case 'update': $this->updateCommand($parameters); break;
|
|
2052
|
+ case 'delete': $this->deleteCommand($parameters); break;
|
|
2053
|
+ case 'headers': $this->headersCommand($parameters); break;
|
|
2054
|
+ }
|
|
2055
|
+ } else {
|
|
2056
|
+ $this->invalidToken();
|
|
2057
|
+ }
|
|
2058
|
+ } else {
|
|
2059
|
+ switch($parameters['action']) {
|
|
2060
|
+ case 'create': $this->createCommand($parameters); break;
|
|
2061
|
+ case 'update': $this->updateCommand($parameters); break;
|
|
2062
|
+ case 'delete': $this->deleteCommand($parameters); break;
|
|
2063
|
+ case 'headers': $this->headersCommand($parameters); break;
|
|
2064
|
+ }
|
|
2065
|
+ }
|
1922
|
2066
|
}
|
1923
|
2067
|
}
|
1924
|
2068
|
}
|
1925
|
|
-
|
1926
|
2069
|
}
|
1927
|
2070
|
|
1928
|
2071
|
// uncomment the lines below when running in stand-alone mode:
|
|
@@ -1930,9 +2073,9 @@ class PHP_CRUD_API {
|
1930
|
2073
|
// $api = new PHP_CRUD_API(array(
|
1931
|
2074
|
// 'dbengine'=>'MySQL',
|
1932
|
2075
|
// 'hostname'=>'localhost',
|
1933
|
|
-// 'username'=>'xxx',
|
1934
|
|
-// 'password'=>'xxx',
|
1935
|
|
-// 'database'=>'xxx',
|
|
2076
|
+// 'username'=>'xxx',
|
|
2077
|
+// 'password'=>'xxx',
|
|
2078
|
+// 'database'=>'xxx',
|
1936
|
2079
|
// 'charset'=>'utf8'
|
1937
|
2080
|
// ));
|
1938
|
2081
|
// $api->executeCommand();
|