Bericht-API: SSO-Migration auf awlauth (JWT -> awl_sso-Cookie)
All checks were successful
Deploy bericht / deploy (push) Successful in 14s
All checks were successful
Deploy bericht / deploy (push) Successful in 14s
- _inc.php: api_authenticate() nutzt awlauth_require(bericht,read) inkl. same-origin-CSRF; CORS (Access-Control-Allow-Origin:*) entfernt (mit Cookies unzulaessig + bei same-origin ueberfluessig). - auth.php: Login ueber awlauth_login/issue -> HttpOnly-Cookie awl_sso, kein Token mehr im Body. - photo.php/pdf.php: GET-Binaer ueber awlauth_verify (kein CSRF, da auch per window.location/<object> geladen); Bearer/jwt-Query-Auth entfernt. - shipments.php: unveraendert (nutzt api_authenticate -> awlauth_require). - neu: logout.php (Single-Logout), verify.php (sliding session). - _jwt.php geloescht (JWT vollstaendig abgeloest). [deploy]
This commit is contained in:
parent
d271b9a9ad
commit
960cee4be4
7 changed files with 87 additions and 216 deletions
51
api/_inc.php
51
api/_inc.php
|
|
@ -1,10 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
/* Gemeinsamer API-Init für alle Bericht-API-Endpoints.
|
/* Gemeinsamer API-Init für alle Bericht-API-Endpoints.
|
||||||
*
|
*
|
||||||
* - Lädt Dolibarr ohne Login (NOLOGIN), wir machen User-Auth selbst per JWT
|
* - Lädt Dolibarr ohne Login (NOLOGIN), Auth per awl_sso-Cookie (zentrales SSO-Modul awlauth)
|
||||||
* - CORS für die PWA
|
|
||||||
* - JSON Request/Response Helpers
|
* - JSON Request/Response Helpers
|
||||||
* - Authentifiziert per JWT (außer auth.php)
|
* - Authentifiziert per awlauth_require (außer auth.php)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('NOLOGIN')) define('NOLOGIN', '1');
|
if (!defined('NOLOGIN')) define('NOLOGIN', '1');
|
||||||
|
|
@ -24,24 +23,12 @@ if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.
|
||||||
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
||||||
if (!$res) die("Include of main fails");
|
if (!$res) die("Include of main fails");
|
||||||
|
|
||||||
require_once __DIR__.'/_jwt.php';
|
|
||||||
require_once __DIR__.'/../class/bericht.class.php';
|
require_once __DIR__.'/../class/bericht.class.php';
|
||||||
require_once __DIR__.'/../lib/bericht.lib.php';
|
require_once __DIR__.'/../lib/bericht.lib.php';
|
||||||
|
|
||||||
// CORS — die PWA läuft auf der gleichen Domain (subpfad), aber wir sind defensiv
|
// Same-Origin: PWA (/baustelle/) und API (/custom/bericht/api/) laufen auf derselben Domain.
|
||||||
$allowed_origin = '*'; // bei Bedarf in Konstante BERICHT_API_CORS_ORIGIN packen
|
// Deshalb KEIN CORS mehr (Access-Control-Allow-Origin: * ist mit Cookies ohnehin unzulaessig).
|
||||||
if (getDolGlobalString('BERICHT_API_CORS_ORIGIN')) {
|
// Das HttpOnly-Cookie awl_sso wird per credentials:'same-origin' automatisch mitgeschickt.
|
||||||
$allowed_origin = getDolGlobalString('BERICHT_API_CORS_ORIGIN');
|
|
||||||
}
|
|
||||||
header('Access-Control-Allow-Origin: '.$allowed_origin);
|
|
||||||
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
|
||||||
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
|
||||||
header('Access-Control-Max-Age: 86400');
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
||||||
http_response_code(204);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
|
@ -71,32 +58,20 @@ function api_input()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lädt den User aus dem JWT und liefert das User-Objekt zurück.
|
* Authentifiziert den Request über das zentrale SSO-Cookie awl_sso.
|
||||||
* Beendet bei ungültigem/fehlendem Token.
|
* awlauth_require prüft Cookie-Signatur, same-origin-Herkunft (CSRF) und die
|
||||||
|
* Berechtigung; bei Fehler beendet es selbst mit 401/403. Der zurückgegebene
|
||||||
|
* User ist voll geladen (inkl. Rechte) — die granularen hasRight('bericht',...)-
|
||||||
|
* Checks in den Endpoints bleiben dadurch unverändert gültig.
|
||||||
*/
|
*/
|
||||||
function api_authenticate($db_param = null)
|
function api_authenticate($db_param = null)
|
||||||
{
|
{
|
||||||
global $db, $user, $conf;
|
global $db, $user, $conf;
|
||||||
if ($db_param) $db = $db_param;
|
if ($db_param) $db = $db_param;
|
||||||
|
|
||||||
$payload = bericht_jwt_from_request();
|
if (!dol_include_once('/awlauth/lib/awlauth.lib.php') || !function_exists('awlauth_require')) {
|
||||||
if (!$payload || empty($payload['sub'])) {
|
api_fail('SSO-Modul (awlauth) nicht verfügbar', 500);
|
||||||
api_fail('Token ungültig oder fehlt', 401);
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
|
||||||
$u = new User($db);
|
|
||||||
if ($u->fetch((int) $payload['sub']) <= 0) {
|
|
||||||
api_fail('User nicht gefunden', 401);
|
|
||||||
}
|
|
||||||
if (empty($u->statut)) {
|
|
||||||
api_fail('User deaktiviert', 401);
|
|
||||||
}
|
|
||||||
$u->loadRights();
|
|
||||||
$user = $u;
|
|
||||||
|
|
||||||
if (!$user->hasRight('bericht', 'read')) {
|
|
||||||
api_fail('Keine Bericht-Rechte', 403);
|
|
||||||
}
|
}
|
||||||
|
$user = awlauth_require('bericht', 'read'); // CSRF + 401/403 + exit inklusive
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
74
api/_jwt.php
74
api/_jwt.php
|
|
@ -1,74 +0,0 @@
|
||||||
<?php
|
|
||||||
/* Mini JWT Helper für die Bericht-API.
|
|
||||||
* HS256 only — kein externes Lib nötig.
|
|
||||||
*
|
|
||||||
* Secret kommt aus $dolibarr_main_instance_unique_id (siehe conf.php),
|
|
||||||
* salt'ed mit "bericht-api-v1".
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!defined('BERICHT_JWT_TTL')) define('BERICHT_JWT_TTL', 30 * 86400); // 30 Tage
|
|
||||||
|
|
||||||
function bericht_jwt_secret()
|
|
||||||
{
|
|
||||||
global $dolibarr_main_instance_unique_id;
|
|
||||||
$base = $dolibarr_main_instance_unique_id ?? 'fallback-secret-do-not-use';
|
|
||||||
return hash('sha256', $base.'|bericht-api-v1');
|
|
||||||
}
|
|
||||||
|
|
||||||
function bericht_b64url_encode($data)
|
|
||||||
{
|
|
||||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
|
|
||||||
}
|
|
||||||
|
|
||||||
function bericht_b64url_decode($data)
|
|
||||||
{
|
|
||||||
return base64_decode(strtr($data, '-_', '+/').str_repeat('=', (4 - strlen($data) % 4) % 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
function bericht_jwt_encode(array $payload)
|
|
||||||
{
|
|
||||||
$header = array('alg' => 'HS256', 'typ' => 'JWT');
|
|
||||||
$h = bericht_b64url_encode(json_encode($header));
|
|
||||||
$p = bericht_b64url_encode(json_encode($payload));
|
|
||||||
$sig = hash_hmac('sha256', $h.'.'.$p, bericht_jwt_secret(), true);
|
|
||||||
return $h.'.'.$p.'.'.bericht_b64url_encode($sig);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bericht_jwt_decode($token)
|
|
||||||
{
|
|
||||||
$parts = explode('.', $token);
|
|
||||||
if (count($parts) !== 3) return null;
|
|
||||||
list($h, $p, $s) = $parts;
|
|
||||||
$expected = bericht_b64url_encode(hash_hmac('sha256', $h.'.'.$p, bericht_jwt_secret(), true));
|
|
||||||
if (!hash_equals($expected, $s)) return null;
|
|
||||||
$payload = json_decode(bericht_b64url_decode($p), true);
|
|
||||||
if (!is_array($payload)) return null;
|
|
||||||
if (isset($payload['exp']) && $payload['exp'] < time()) return null;
|
|
||||||
return $payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Liest und validiert das Authorization: Bearer <jwt> Header.
|
|
||||||
* @return array|null decoded payload
|
|
||||||
*/
|
|
||||||
function bericht_jwt_from_request()
|
|
||||||
{
|
|
||||||
$hdr = '';
|
|
||||||
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
|
|
||||||
$hdr = $_SERVER['HTTP_AUTHORIZATION'];
|
|
||||||
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
|
||||||
$hdr = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
|
|
||||||
} elseif (function_exists('apache_request_headers')) {
|
|
||||||
$h = apache_request_headers();
|
|
||||||
if (isset($h['Authorization'])) $hdr = $h['Authorization'];
|
|
||||||
}
|
|
||||||
$token = '';
|
|
||||||
if ($hdr && stripos($hdr, 'bearer ') === 0) {
|
|
||||||
$token = trim(substr($hdr, 7));
|
|
||||||
} elseif (!empty($_GET['jwt'])) {
|
|
||||||
// Fallback: JWT als Query-Param (fuer <img>, <object>, <iframe> die keinen Authorization-Header schicken koennen)
|
|
||||||
$token = (string) $_GET['jwt'];
|
|
||||||
}
|
|
||||||
if (!$token) return null;
|
|
||||||
return bericht_jwt_decode($token);
|
|
||||||
}
|
|
||||||
54
api/auth.php
54
api/auth.php
|
|
@ -1,61 +1,33 @@
|
||||||
<?php
|
<?php
|
||||||
/* POST /api/auth.php
|
/* POST /api/auth.php — Login über das zentrale SSO-Modul awlauth.
|
||||||
* Body: { "login": "...", "password": "..." }
|
* Body: { "login": "...", "password": "..." }
|
||||||
* Response: { "token": "...", "user": { id, login, fullname }, "expires": <unix> }
|
* Setzt bei Erfolg das domainweite HttpOnly-Cookie awl_sso (gilt für alle AWL-Apps).
|
||||||
|
* Response: { "ok": true, "user": { id, login, name, admin } } — KEIN Token mehr im Body.
|
||||||
*/
|
*/
|
||||||
require_once __DIR__.'/_inc.php';
|
require_once __DIR__.'/_inc.php';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') api_fail('POST erforderlich', 405);
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') api_fail('POST erforderlich', 405);
|
||||||
|
|
||||||
|
if (!dol_include_once('/awlauth/lib/awlauth.lib.php') || !function_exists('awlauth_login')) {
|
||||||
|
api_fail('SSO-Modul (awlauth) nicht verfügbar', 500);
|
||||||
|
}
|
||||||
|
|
||||||
$in = api_input();
|
$in = api_input();
|
||||||
$login = trim($in['login'] ?? '');
|
|
||||||
$pass = (string) ($in['password'] ?? '');
|
|
||||||
if (empty($login) || empty($pass)) api_fail('login + password erforderlich');
|
|
||||||
|
|
||||||
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
// Login inkl. Rate-Limit, Passwortprüfung (dol_verifyHash) und Nur-Interne-User-Check
|
||||||
|
$r = awlauth_login(trim($in['login'] ?? ''), (string) ($in['password'] ?? ''));
|
||||||
|
if (!$r['success']) api_fail($r['error'], $r['http']);
|
||||||
|
|
||||||
$u = new User($db);
|
$u = $r['user'];
|
||||||
if ($u->fetch('', $login) <= 0) api_fail('Login fehlgeschlagen', 401);
|
|
||||||
|
|
||||||
// Passwort prüfen — Dolibarr's checkPassword braucht den schon geladenen User
|
|
||||||
if (!dol_verifyHash($pass, $u->pass_indatabase_crypted ?: $u->pass_indatabase)) {
|
|
||||||
// Fallback: alter Hash-Vergleich
|
|
||||||
if (md5($pass) !== $u->pass_indatabase) {
|
|
||||||
api_fail('Login fehlgeschlagen', 401);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($u->statut)) api_fail('User deaktiviert', 403);
|
|
||||||
|
|
||||||
$u->loadRights();
|
|
||||||
if (!$u->hasRight('bericht', 'read')) api_fail('Keine Bericht-Rechte', 403);
|
if (!$u->hasRight('bericht', 'read')) api_fail('Keine Bericht-Rechte', 403);
|
||||||
|
|
||||||
// JWT erstellen
|
awlauth_issue($u); // HttpOnly-Cookie awl_sso setzen
|
||||||
$exp = time() + BERICHT_JWT_TTL;
|
|
||||||
$payload = array(
|
|
||||||
'sub' => (int) $u->id,
|
|
||||||
'login' => $u->login,
|
|
||||||
'name' => method_exists($u, 'getFullName') ? $u->getFullName($langs ?? null) : $u->login,
|
|
||||||
'iat' => time(),
|
|
||||||
'exp' => $exp,
|
|
||||||
'iss' => 'bericht-api',
|
|
||||||
'perms' => array(
|
|
||||||
'read' => (bool) $u->hasRight('bericht', 'read'),
|
|
||||||
'write' => (bool) $u->hasRight('bericht', 'write'),
|
|
||||||
'delete' => (bool) $u->hasRight('bericht', 'delete'),
|
|
||||||
'admin' => (bool) $u->hasRight('bericht', 'admin'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
$token = bericht_jwt_encode($payload);
|
|
||||||
|
|
||||||
api_ok(array(
|
api_ok(array(
|
||||||
'token' => $token,
|
|
||||||
'expires' => $exp,
|
|
||||||
'user' => array(
|
'user' => array(
|
||||||
'id' => (int) $u->id,
|
'id' => (int) $u->id,
|
||||||
'login' => $u->login,
|
'login' => $u->login,
|
||||||
'name' => $payload['name'],
|
'name' => $u->getFullName($langs ?? null),
|
||||||
'admin' => (bool) ($u->admin ?? false),
|
'admin' => (bool) ($u->admin ?? false),
|
||||||
),
|
),
|
||||||
'perms' => $payload['perms'],
|
|
||||||
));
|
));
|
||||||
|
|
|
||||||
12
api/logout.php
Normal file
12
api/logout.php
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
/* POST /api/logout.php — löscht das zentrale SSO-Cookie awl_sso.
|
||||||
|
* Meldet den Benutzer damit aus allen AWL-Apps ab (Single-Logout).
|
||||||
|
*/
|
||||||
|
require_once __DIR__.'/_inc.php';
|
||||||
|
|
||||||
|
if (!dol_include_once('/awlauth/lib/awlauth.lib.php') || !function_exists('awlauth_clear_cookie')) {
|
||||||
|
api_fail('SSO-Modul (awlauth) nicht verfügbar', 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
awlauth_clear_cookie();
|
||||||
|
api_ok();
|
||||||
40
api/pdf.php
40
api/pdf.php
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
/* GET /api/pdf.php?id=<bericht_id>&jwt=<token>
|
/* GET /api/pdf.php?id=<bericht_id>
|
||||||
* Liefert das finale PDF eines Berichts zur Anzeige/Download.
|
* Liefert das finale PDF eines Berichts zur Anzeige/Download.
|
||||||
|
* Auth über das awl_sso-Cookie (same-origin).
|
||||||
* Wenn noch kein final_pdf_path existiert oder die Datei fehlt,
|
* Wenn noch kein final_pdf_path existiert oder die Datei fehlt,
|
||||||
* wird direkt eine temporäre Vorschau generiert (wie preview_pdf.php).
|
* wird direkt eine temporäre Vorschau generiert (wie preview_pdf.php).
|
||||||
*/
|
*/
|
||||||
|
|
@ -21,42 +22,25 @@ if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.
|
||||||
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
||||||
if (!$res) die("Include of main fails");
|
if (!$res) die("Include of main fails");
|
||||||
|
|
||||||
require_once __DIR__.'/_jwt.php';
|
|
||||||
require_once __DIR__.'/../class/bericht.class.php';
|
require_once __DIR__.'/../class/bericht.class.php';
|
||||||
require_once __DIR__.'/../lib/bericht.lib.php';
|
require_once __DIR__.'/../lib/bericht.lib.php';
|
||||||
|
|
||||||
// JWT robust lesen
|
// Auth über das zentrale SSO-Cookie awl_sso. awlauth_verify (OHNE CSRF), weil
|
||||||
$token_str = '';
|
// dieser reine GET-Read auch per window.location/<object> geladen wird.
|
||||||
$hdr = $_SERVER['HTTP_AUTHORIZATION'] ?? ($_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '');
|
if (!dol_include_once('/awlauth/lib/awlauth.lib.php') || !function_exists('awlauth_verify')) {
|
||||||
if (!$hdr && function_exists('apache_request_headers')) {
|
http_response_code(500);
|
||||||
foreach (apache_request_headers() as $k => $v) {
|
header('Content-Type: text/plain');
|
||||||
if (strcasecmp($k, 'Authorization') === 0) { $hdr = $v; break; }
|
echo 'SSO-Modul (awlauth) nicht verfügbar';
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
}
|
$user = awlauth_verify();
|
||||||
if ($hdr && stripos($hdr, 'bearer ') === 0) $token_str = trim(substr($hdr, 7));
|
if (!$user || !$user->hasRight('bericht', 'read')) {
|
||||||
if (!$token_str && !empty($_GET['jwt'])) $token_str = (string) $_GET['jwt'];
|
|
||||||
|
|
||||||
$payload = $token_str ? bericht_jwt_decode($token_str) : null;
|
|
||||||
if (!$payload || empty($payload['sub'])) {
|
|
||||||
http_response_code(401);
|
http_response_code(401);
|
||||||
header('Content-Type: text/plain');
|
header('Content-Type: text/plain');
|
||||||
echo 'Token ungültig';
|
echo 'Nicht angemeldet';
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
|
||||||
$u = new User($db);
|
|
||||||
if ($u->fetch((int) $payload['sub']) <= 0 || empty($u->statut)) {
|
|
||||||
http_response_code(401);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
$u->loadRights();
|
|
||||||
if (!$u->hasRight('bericht', 'read')) {
|
|
||||||
http_response_code(403);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
$user = $u;
|
|
||||||
|
|
||||||
$id = (int) ($_GET['id'] ?? 0);
|
$id = (int) ($_GET['id'] ?? 0);
|
||||||
if (!$id) { http_response_code(400); exit; }
|
if (!$id) { http_response_code(400); exit; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
* size=small|mini (optional, nutzt automatisch das Thumb)
|
* size=small|mini (optional, nutzt automatisch das Thumb)
|
||||||
*/
|
*/
|
||||||
// Dieser Endpoint liefert Binärdaten aus — KEIN JSON Content-Type!
|
// Dieser Endpoint liefert Binärdaten aus — KEIN JSON Content-Type!
|
||||||
// Deshalb nicht _inc.php direkt nutzen, sondern JWT + Dolibarr manuell laden.
|
// Deshalb nicht _inc.php nutzen, sondern awlauth + Dolibarr manuell laden.
|
||||||
if (!defined('NOLOGIN')) define('NOLOGIN', '1');
|
if (!defined('NOLOGIN')) define('NOLOGIN', '1');
|
||||||
if (!defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1');
|
if (!defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1');
|
||||||
if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1');
|
if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1');
|
||||||
|
|
@ -29,47 +29,25 @@ if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.
|
||||||
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
|
||||||
if (!$res) die("Include of main fails");
|
if (!$res) die("Include of main fails");
|
||||||
|
|
||||||
require_once __DIR__.'/_jwt.php';
|
|
||||||
require_once __DIR__.'/../lib/bericht.lib.php';
|
require_once __DIR__.'/../lib/bericht.lib.php';
|
||||||
|
|
||||||
// Support Token via Header ODER Query-String (für <img src> ohne Header)
|
// Auth über das zentrale SSO-Cookie awl_sso. Bewusst awlauth_verify (OHNE CSRF),
|
||||||
$token_str = '';
|
// weil dieser reine GET-Read auch per window.location/<a href> geladen wird
|
||||||
$hdr = $_SERVER['HTTP_AUTHORIZATION'] ?? ($_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '');
|
// (Download-Link, Audio-Element) und dort kein X-Requested-With setzbar ist.
|
||||||
if (!$hdr && function_exists('apache_request_headers')) {
|
if (!dol_include_once('/awlauth/lib/awlauth.lib.php') || !function_exists('awlauth_verify')) {
|
||||||
$h = apache_request_headers();
|
http_response_code(500);
|
||||||
foreach ($h as $k => $v) {
|
header('Content-Type: text/plain');
|
||||||
if (strcasecmp($k, 'Authorization') === 0) { $hdr = $v; break; }
|
echo 'SSO-Modul (awlauth) nicht verfügbar';
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
}
|
$user = awlauth_verify();
|
||||||
if ($hdr && stripos($hdr, 'bearer ') === 0) $token_str = trim(substr($hdr, 7));
|
if (!$user || !$user->hasRight('bericht', 'read')) {
|
||||||
if (!$token_str && !empty($_GET['jwt'])) $token_str = (string) $_GET['jwt'];
|
|
||||||
if (!$token_str && !empty($_GET['token']) && preg_match('/^[A-Za-z0-9_.-]+$/', $_GET['token'])) $token_str = $_GET['token'];
|
|
||||||
|
|
||||||
$payload = $token_str ? bericht_jwt_decode($token_str) : null;
|
|
||||||
if (!$payload || empty($payload['sub'])) {
|
|
||||||
http_response_code(401);
|
http_response_code(401);
|
||||||
header('Content-Type: text/plain');
|
header('Content-Type: text/plain');
|
||||||
echo 'Token ungültig oder fehlt';
|
echo 'Nicht angemeldet';
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
|
||||||
$u = new User($db);
|
|
||||||
if ($u->fetch((int) $payload['sub']) <= 0 || empty($u->statut)) {
|
|
||||||
http_response_code(401);
|
|
||||||
header('Content-Type: text/plain');
|
|
||||||
echo 'User ungültig';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
$u->loadRights();
|
|
||||||
if (!$u->hasRight('bericht', 'read')) {
|
|
||||||
http_response_code(403);
|
|
||||||
header('Content-Type: text/plain');
|
|
||||||
echo 'Permission denied';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
$user = $u;
|
|
||||||
|
|
||||||
$relpath = (string) ($_GET['relpath'] ?? '');
|
$relpath = (string) ($_GET['relpath'] ?? '');
|
||||||
$size = (string) ($_GET['size'] ?? '');
|
$size = (string) ($_GET['size'] ?? '');
|
||||||
|
|
||||||
|
|
@ -112,7 +90,6 @@ $filename = $download ? basename($full) : '';
|
||||||
header('Content-Type: '.$mime);
|
header('Content-Type: '.$mime);
|
||||||
header('Content-Length: '.filesize($full));
|
header('Content-Length: '.filesize($full));
|
||||||
header('Cache-Control: private, max-age=3600');
|
header('Cache-Control: private, max-age=3600');
|
||||||
header('Access-Control-Allow-Origin: *');
|
|
||||||
if ($download) {
|
if ($download) {
|
||||||
header('Content-Disposition: attachment; filename="'.addslashes($filename).'"');
|
header('Content-Disposition: attachment; filename="'.addslashes($filename).'"');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
api/verify.php
Normal file
25
api/verify.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
/* GET /api/verify.php — prüft das awl_sso-Cookie und erneuert die Session (sliding).
|
||||||
|
* Ersatz für die frühere lokale Token-Prüfung (ensureAuth) im Frontend.
|
||||||
|
* Bewusst awlauth_verify (ohne CSRF) — reiner Lese-/Renew-Aufruf.
|
||||||
|
*/
|
||||||
|
require_once __DIR__.'/_inc.php';
|
||||||
|
|
||||||
|
if (!dol_include_once('/awlauth/lib/awlauth.lib.php') || !function_exists('awlauth_verify')) {
|
||||||
|
api_fail('SSO-Modul (awlauth) nicht verfügbar', 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$u = awlauth_verify();
|
||||||
|
if (!$u || !$u->hasRight('bericht', 'read')) {
|
||||||
|
api_fail('Nicht angemeldet', 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
awlauth_issue($u); // gleitende Verlängerung der Gültigkeit
|
||||||
|
|
||||||
|
api_ok(array(
|
||||||
|
'user' => array(
|
||||||
|
'id' => (int) $u->id,
|
||||||
|
'login' => $u->login,
|
||||||
|
'name' => $u->getFullName($langs ?? null),
|
||||||
|
),
|
||||||
|
));
|
||||||
Loading…
Reference in a new issue