114 lines
3.8 KiB
PHP
114 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\API\v1\Voter;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Controllers\Util;
|
|
use App\Support\ApiTokenLifetime;
|
|
use App\Support\JwtVerifier;
|
|
use App\Voter;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
class SsoLoginController extends Controller
|
|
{
|
|
public function login(Request $request)
|
|
{
|
|
$token = $request->query('token');
|
|
|
|
if (! $token) {
|
|
return $this->redirectToLogin('Token SSO tidak sah.', 'token_invalid');
|
|
}
|
|
|
|
$secret = config('services.mykopkb.sso_secret');
|
|
if (! $secret) {
|
|
return $this->redirectToLogin(
|
|
app()->environment('local', 'development')
|
|
? 'MYKOPKB_SSO_SECRET belum dikonfigurasi dalam .env.'
|
|
: 'Token SSO tamat tempoh atau tidak sah.',
|
|
'token_invalid'
|
|
);
|
|
}
|
|
|
|
$payload = JwtVerifier::verify($token, $secret, [
|
|
'issuer' => config('services.mykopkb.sso_issuer', 'mykopkb'),
|
|
'audience' => config('services.mykopkb.sso_audience', 'e-vote'),
|
|
]);
|
|
|
|
if (! $payload) {
|
|
return $this->redirectToLogin('Token SSO tamat tempoh atau tidak sah.', 'token_invalid');
|
|
}
|
|
|
|
$jti = $payload['jti'] ?? null;
|
|
if (! $jti || Cache::has("sso_jti:$jti")) {
|
|
return $this->redirectToLogin('Token SSO telah digunakan.', 'token_used');
|
|
}
|
|
|
|
$icNumber = preg_replace('/[\s-]+/', '', (string) ($payload['ic_number'] ?? ''));
|
|
$memberNumber = trim((string) ($payload['member_number'] ?? ''));
|
|
|
|
if ($icNumber === '' || $memberNumber === '') {
|
|
return $this->redirectToLogin('Token SSO tidak sah.', 'token_invalid');
|
|
}
|
|
|
|
$voter = Voter::query()
|
|
->where('no_kp', $icNumber)
|
|
->where('no_anggota', $memberNumber)
|
|
->where('election_id', Util::getCurrentElection())
|
|
->first();
|
|
|
|
if (! $voter) {
|
|
activity()
|
|
->withProperties([
|
|
'ic_number' => $icNumber,
|
|
'member_number' => $memberNumber,
|
|
'election_id' => Util::getCurrentElection(),
|
|
'ip' => $request->ip(),
|
|
'user_agent' => $request->userAgent(),
|
|
])
|
|
->log('voter sso login rejected: not in current election');
|
|
|
|
return $this->redirectToLogin(
|
|
'Akaun pengundi tidak dijumpai untuk pilihan raya semasa. Sila daftar di kaunter IT atau log masuk secara manual.',
|
|
'voter_not_found'
|
|
);
|
|
}
|
|
|
|
Cache::put("sso_jti:$jti", true, now()->addMinutes(5));
|
|
|
|
ApiTokenLifetime::revokeActiveTokens($voter);
|
|
|
|
$passportToken = $voter->createToken('SSO Login', ['vote'])->accessToken;
|
|
$meta = ApiTokenLifetime::loginMeta('voter');
|
|
|
|
activity()
|
|
->performedOn($voter)
|
|
->withProperties([
|
|
'election_id' => Util::getCurrentElection(),
|
|
'voter_id' => $voter->id,
|
|
'voter_name' => $voter->name,
|
|
'no_kp' => $voter->no_kp,
|
|
'no_anggota' => $voter->no_anggota,
|
|
'sso_sub' => $payload['sub'] ?? null,
|
|
'ip' => $request->ip(),
|
|
'user_agent' => $request->userAgent(),
|
|
])
|
|
->log("voter sso login: {$voter->name}");
|
|
|
|
$query = http_build_query([
|
|
'sso_token' => $passportToken,
|
|
'token_expires_at' => $meta['token_expires_at'],
|
|
]);
|
|
|
|
return redirect('/login?'.$query);
|
|
}
|
|
|
|
private function redirectToLogin(string $message, string $code = 'sso_error')
|
|
{
|
|
return redirect('/login?'.http_build_query([
|
|
'sso_error' => $message,
|
|
'sso_error_code' => $code,
|
|
]));
|
|
}
|
|
}
|