You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
65 lines
1.7 KiB
65 lines
1.7 KiB
<?php |
|
|
|
namespace App\Services; |
|
|
|
use Firebase\JWT\JWT; |
|
use Firebase\JWT\Key; |
|
use UnexpectedValueException; |
|
|
|
class LdapJwtService |
|
{ |
|
public function issue(string $username, bool $isAdmin, array $groups): string |
|
{ |
|
$scopes = $isAdmin |
|
? ['admin'] |
|
: ['ldap:read']; |
|
|
|
$now = time(); |
|
$payload = [ |
|
'iss' => config('app.url'), |
|
'sub' => $username, |
|
'typ' => 'ldap', |
|
'is_admin' => $isAdmin, |
|
'groups' => $groups, |
|
'scopes' => $scopes, |
|
'iat' => $now, |
|
'exp' => $now + config('api.ldap_jwt_ttl'), |
|
]; |
|
|
|
return JWT::encode($payload, $this->secret(), 'HS256'); |
|
} |
|
|
|
/** |
|
* @return array{username: string, is_admin: bool, scopes: list<string>}|null |
|
*/ |
|
public function validate(string $jwt): ?array |
|
{ |
|
try { |
|
$decoded = JWT::decode($jwt, new Key($this->secret(), 'HS256')); |
|
$payload = (array) $decoded; |
|
|
|
if (($payload['typ'] ?? '') !== 'ldap') { |
|
return null; |
|
} |
|
|
|
return [ |
|
'username' => (string) ($payload['sub'] ?? ''), |
|
'is_admin' => (bool) ($payload['is_admin'] ?? false), |
|
'scopes' => array_values((array) ($payload['scopes'] ?? [])), |
|
]; |
|
} catch (UnexpectedValueException|\DomainException|\InvalidArgumentException) { |
|
return null; |
|
} |
|
} |
|
|
|
private function secret(): string |
|
{ |
|
$key = config('app.key'); |
|
|
|
if (str_starts_with($key, 'base64:')) { |
|
return base64_decode(substr($key, 7), true) ?: $key; |
|
} |
|
|
|
return $key; |
|
} |
|
}
|
|
|