135 lines
4.1 KiB
PHP
135 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace Dabestaniha\AuthenticateBridge\App\Http\Controllers;
|
|
|
|
use Dabestaniha\AuthenticateBridge\App\Http\Requests\MahakAuthenticateRequest;
|
|
use Dabestaniha\AuthenticateBridge\App\Support\JwtDecoder;
|
|
use RuntimeException;
|
|
use Throwable;
|
|
use UnexpectedValueException;
|
|
|
|
class AuthenticateController extends InvocableController
|
|
{
|
|
private array $debugContext = [];
|
|
|
|
public function __invoke(MahakAuthenticateRequest $request)
|
|
{
|
|
$token = $request->string('token');
|
|
|
|
if (mahak_debug_enabled()) {
|
|
$this->debugContext['jwt_timestamps'] = $this->inspectJwtTimestamps($token);
|
|
}
|
|
|
|
$payload = $this->decrypt_jwt_token($token);
|
|
|
|
$identifier_name = get_configured_option('user-identifier');
|
|
$identifier_value = $payload[$identifier_name] ?? null;
|
|
|
|
$name = $payload['name'] ?? config('mahak.translates.new-user');
|
|
$user_id = $this->find_or_create_user($identifier_name, $identifier_value, $name);
|
|
|
|
$this->login_user($user_id);
|
|
|
|
$redirect_path = get_configured_option('after-login-route');
|
|
wp_redirect(home_url($redirect_path));
|
|
exit();
|
|
}
|
|
|
|
public function decrypt_jwt_token(string $token): array
|
|
{
|
|
$jwt_secret = get_configured_option('jwt-secret');
|
|
|
|
$decoded = JwtDecoder::decodeHs256($token, $jwt_secret);
|
|
$data = $decoded['data'] ?? null;
|
|
|
|
if (!is_array($data)) {
|
|
throw new UnexpectedValueException('JWT data must be an object.');
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
public function find_or_create_user(string $identifier_name, string $identifier_value, string $name): int
|
|
{
|
|
$user = get_user_by($identifier_name, $identifier_value);
|
|
|
|
if ($user) {
|
|
return $user->ID;
|
|
}
|
|
$random_password = wp_generate_password(12, true);
|
|
$username = $identifier_value;
|
|
$email = $identifier_name === 'email' ? $identifier_value : '';
|
|
|
|
if (username_exists($username)) {
|
|
$username .= '_'.wp_generate_password(4, false);
|
|
}
|
|
|
|
$user_id = wp_create_user($username, $random_password, $email);
|
|
|
|
if (is_wp_error($user_id)) {
|
|
throw new RuntimeException(
|
|
'WordPress could not create the user: '.$user_id->get_error_message()
|
|
);
|
|
}
|
|
|
|
$updated_user_id = wp_update_user([
|
|
'ID' => $user_id,
|
|
'display_name' => $name,
|
|
]);
|
|
|
|
if (is_wp_error($updated_user_id)) {
|
|
throw new RuntimeException(
|
|
'WordPress could not update the user: '.$updated_user_id->get_error_message()
|
|
);
|
|
}
|
|
|
|
return $user_id;
|
|
}
|
|
|
|
protected function handleException(Throwable $exception): void
|
|
{
|
|
$status = $exception->getCode() === 403 ? 403 : 500;
|
|
$fallbackView = $exception instanceof UnexpectedValueException ? 'invalid-token' : 'server-error';
|
|
|
|
mahak_render_error($exception, $status, $fallbackView, $this->debugContext);
|
|
}
|
|
|
|
private function inspectJwtTimestamps(string $token): array
|
|
{
|
|
$segments = explode('.', $token);
|
|
|
|
if (count($segments) !== 3) {
|
|
return [];
|
|
}
|
|
|
|
$encodedPayload = strtr($segments[1], '-_', '+/');
|
|
$encodedPayload .= str_repeat('=', (4 - strlen($encodedPayload) % 4) % 4);
|
|
$json = base64_decode($encodedPayload, true);
|
|
$payload = $json === false ? null : json_decode($json, true);
|
|
|
|
if (!is_array($payload)) {
|
|
return [];
|
|
}
|
|
|
|
$timestamps = [];
|
|
|
|
foreach (['iat', 'nbf', 'exp'] as $claim) {
|
|
if (array_key_exists($claim, $payload)) {
|
|
$value = is_scalar($payload[$claim]) ? (string) $payload[$claim] : '[non-scalar]';
|
|
$timestamps[$claim] = strlen($value) > 64 ? substr($value, 0, 64).'…' : $value;
|
|
}
|
|
}
|
|
|
|
return $timestamps;
|
|
}
|
|
|
|
|
|
public function login_user(int $user_id): bool
|
|
{
|
|
wp_set_auth_cookie($user_id);
|
|
wp_set_current_user($user_id);
|
|
do_action('wp_login', get_userdata($user_id)->user_login, get_userdata($user_id));
|
|
return true;
|
|
}
|
|
}
|