Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 699f0a015d |
@@ -1,155 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Modules\Authentication\Classes;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class Uim
|
|
||||||
{
|
|
||||||
private string $serviceHost;
|
|
||||||
private int $servicePort;
|
|
||||||
private string $appId;
|
|
||||||
private string $serverAddress;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $serviceHost The host address of the user verification service
|
|
||||||
* @param int $servicePort The port of the user verification service
|
|
||||||
* @param string $appId The application ID
|
|
||||||
* @param string $serverAddress The server address
|
|
||||||
*/
|
|
||||||
public function __construct(string $serviceHost, int $servicePort, string $appId, string $serverAddress)
|
|
||||||
{
|
|
||||||
$this->serviceHost = $serviceHost;
|
|
||||||
$this->servicePort = $servicePort;
|
|
||||||
$this->appId = $appId;
|
|
||||||
$this->serverAddress = $serverAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a user's credentials
|
|
||||||
*
|
|
||||||
* @param string $userId The user ID
|
|
||||||
* @param string $password The user password
|
|
||||||
*
|
|
||||||
* @return string The verification response
|
|
||||||
* @throws Exception If connection fails or other errors occur
|
|
||||||
*/
|
|
||||||
public function verify(string $userId, string $password)
|
|
||||||
: string
|
|
||||||
{
|
|
||||||
$socket = $this->openSecureConnection();
|
|
||||||
|
|
||||||
$postData = $this->buildPostData($userId, $password);
|
|
||||||
$this->sendHttpRequest($socket, $postData);
|
|
||||||
|
|
||||||
$response = $this->readResponse($socket);
|
|
||||||
fclose($socket);
|
|
||||||
|
|
||||||
return $this->decodeHexResponse($response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a secure connection to the verification service
|
|
||||||
*
|
|
||||||
* @return resource The socket connection
|
|
||||||
* @throws Exception If connection fails
|
|
||||||
*/
|
|
||||||
private function openSecureConnection()
|
|
||||||
{
|
|
||||||
$errno = 0;
|
|
||||||
$errstr = '';
|
|
||||||
$socket = @fsockopen("tcp://" . $this->serviceHost, $this->servicePort, $errno, $errstr, 30);
|
|
||||||
|
|
||||||
if (!$socket) {
|
|
||||||
throw new Exception("Connection failed: $errstr ($errno)");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the form data for the verification request
|
|
||||||
*
|
|
||||||
* @param string $userId The user ID
|
|
||||||
* @param string $password The user password
|
|
||||||
*
|
|
||||||
* @return string The URL-encoded form data
|
|
||||||
*/
|
|
||||||
private function buildPostData(string $userId, string $password)
|
|
||||||
: string
|
|
||||||
{
|
|
||||||
return http_build_query([
|
|
||||||
'appsid' => $this->appId,
|
|
||||||
'loginid' => $userId,
|
|
||||||
'passwd' => $password,
|
|
||||||
'addr' => $this->serverAddress,
|
|
||||||
'version' => 2
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the HTTP request to the verification service
|
|
||||||
*
|
|
||||||
* @param resource $socket The socket connection
|
|
||||||
* @param string $postData The data to send
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function sendHttpRequest($socket, string $postData)
|
|
||||||
: void
|
|
||||||
{
|
|
||||||
fwrite($socket, "POST /user_verification_dev.php HTTP/1.0\r\n");
|
|
||||||
fwrite($socket, "Host: {$this->serviceHost}\r\n");
|
|
||||||
fwrite($socket, "Content-type: application/x-www-form-urlencoded\r\n");
|
|
||||||
fwrite($socket, "Content-length: " . strlen($postData) . "\r\n");
|
|
||||||
fwrite($socket, "Accept: */*\r\n");
|
|
||||||
fwrite($socket, "\r\n");
|
|
||||||
fwrite($socket, "$postData\r\n");
|
|
||||||
fwrite($socket, "\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the response from the verification service
|
|
||||||
*
|
|
||||||
* @param resource $socket The socket connection
|
|
||||||
*
|
|
||||||
* @return string The response body
|
|
||||||
*/
|
|
||||||
private function readResponse($socket)
|
|
||||||
: string
|
|
||||||
{
|
|
||||||
// Skip headers
|
|
||||||
$headers = "";
|
|
||||||
while ($str = trim(fgets($socket, 4096))) {
|
|
||||||
$headers .= "$str\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read body
|
|
||||||
$body = "";
|
|
||||||
while (!feof($socket)) {
|
|
||||||
$body .= fgets($socket, 4096);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $body;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode a hex-encoded response
|
|
||||||
*
|
|
||||||
* @param string $data The hex-encoded data
|
|
||||||
*
|
|
||||||
* @return string The decoded string
|
|
||||||
*/
|
|
||||||
private function decodeHexResponse(string $data)
|
|
||||||
: string
|
|
||||||
{
|
|
||||||
$text = '';
|
|
||||||
$total = strlen($data);
|
|
||||||
|
|
||||||
for ($j = 0; $j < $total; $j += 2) {
|
|
||||||
$text .= chr(hexdec(substr($data, $j, 2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
use Modules\Authentication\Classes\Uim;
|
|
||||||
|
|
||||||
if (!function_exists('verify_user')) {
|
|
||||||
function verify_user($id, $passwd, $SERVER_ADDR, $IPUserManager, $portUserManager, $appId)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$verifier = new Uim($IPUserManager, $portUserManager, $appId, $SERVER_ADDR);
|
|
||||||
return $verifier->verify($id, $passwd);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// Handle error more gracefully than the original die()
|
|
||||||
error_log("User verification error: " . $e->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
use Illuminate\Support\Facades\RateLimiter;
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Modules\Basicdata\Models\Branch;
|
|
||||||
use Modules\Usermanagement\Models\User;
|
|
||||||
|
|
||||||
class LoginRequest extends FormRequest
|
class LoginRequest extends FormRequest
|
||||||
{
|
{
|
||||||
@@ -27,14 +25,6 @@
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function messages()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'login.required' => 'User tidak boleh kosong',
|
|
||||||
'password.required' => 'Password tidak boleh kosong',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to authenticate the request's credentials.
|
* Attempt to authenticate the request's credentials.
|
||||||
*
|
*
|
||||||
@@ -42,113 +32,28 @@
|
|||||||
*
|
*
|
||||||
* @throws \Illuminate\Validation\ValidationException
|
* @throws \Illuminate\Validation\ValidationException
|
||||||
*/
|
*/
|
||||||
public function authenticate(): void
|
public function authenticate()
|
||||||
|
: void
|
||||||
{
|
{
|
||||||
$this->ensureIsNotRateLimited();
|
$this->ensureIsNotRateLimited();
|
||||||
|
|
||||||
$credentials = $this->only('login', 'password');
|
$credentials = $this->only('login', 'password');
|
||||||
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
||||||
|
|
||||||
$authData = [
|
$authData = [
|
||||||
$loginField => $credentials['login'],
|
$loginField => $credentials['login'],
|
||||||
'password' => $credentials['password'],
|
'password' => $credentials['password'],
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($_ENV['METHOD_AUTH'] == 'uim') {
|
if (!Auth::attempt($authData, $this->boolean('remember'))) {
|
||||||
$this->userIdManagemeent($credentials);
|
RateLimiter::hit($this->throttleKey());
|
||||||
} else {
|
|
||||||
if (!Auth::attempt($authData, $this->boolean('remember'))) {
|
|
||||||
RateLimiter::hit($this->throttleKey());
|
|
||||||
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
|
||||||
$user = User::where($loginField, $credentials['login'])->first();
|
|
||||||
|
|
||||||
$messages = [];
|
throw ValidationException::withMessages([
|
||||||
if ($user) {
|
'login' => trans('auth.failed'),
|
||||||
$messages['password'] = 'Password tidak sesuai';
|
]);
|
||||||
} else {
|
|
||||||
$messages['login'] = 'Email/NIK tidak ditemukan';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw ValidationException::withMessages($messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
RateLimiter::clear($this->throttleKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticate user through user manager
|
|
||||||
*
|
|
||||||
* @param array $credentials
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
protected function userIdManagemeent($credentials)
|
|
||||||
{
|
|
||||||
$userArray = [];
|
|
||||||
$id = $credentials['login'];
|
|
||||||
$passwd = $credentials['password'];
|
|
||||||
$SERVER_ADDR = request()->ip();
|
|
||||||
$IPUserManager = $_ENV['IP_USER_MANAGER'];
|
|
||||||
$portUserManager = $_ENV['PORT_USER_MANAGER'];
|
|
||||||
$appId = $_ENV['APP_ID'];
|
|
||||||
|
|
||||||
$userData = verify_user($id, $passwd, $SERVER_ADDR, $IPUserManager, $portUserManager, $appId);
|
|
||||||
|
|
||||||
if (strlen($userData) > 1) {
|
|
||||||
$userRawArray = explode("\t", $userData);
|
|
||||||
|
|
||||||
foreach ($userRawArray as $rval) {
|
|
||||||
[$key, $val] = explode('=', $rval);
|
|
||||||
$userArray[0][$key] = $val;
|
|
||||||
}
|
|
||||||
// Use the login value to find the user
|
|
||||||
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
|
||||||
|
|
||||||
$kodeCabang = $userArray[0]['KD_CABANG']; // Example value containing the code
|
|
||||||
$lastFourDigits = substr($kodeCabang, -4); // Gets the last 4 characters
|
|
||||||
$branch = Branch::where('code', 'LIKE', '%' . $lastFourDigits)->first();
|
|
||||||
|
|
||||||
session()->put($userArray[0]);
|
|
||||||
if ($branch) {
|
|
||||||
session()->put('branch_id', $branch->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = User::updateOrCreate(
|
|
||||||
[$loginField => $credentials['login']],
|
|
||||||
[
|
|
||||||
'name' => $userArray[0]['NAMA_USER'],
|
|
||||||
'email' => $loginField === 'email' ? $credentials['login'] : null,
|
|
||||||
'nik' => $loginField === 'nik' ? $credentials['login'] : null,
|
|
||||||
'password' => bcrypt($credentials['password']),
|
|
||||||
'branch_id' => $branch ? $branch->id : null,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assign role based on user group code
|
|
||||||
$role = match($userArray[0]['KD_GROUP']) {
|
|
||||||
'001' => 'administrator',
|
|
||||||
default => 'customer_service'
|
|
||||||
};
|
|
||||||
|
|
||||||
$user->syncRoles($role);
|
|
||||||
|
|
||||||
Auth::loginUsingId($user->id, true);
|
|
||||||
$this->session()->regenerate();
|
|
||||||
|
|
||||||
RateLimiter::clear($this->throttleKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authentication failed
|
RateLimiter::clear($this->throttleKey());
|
||||||
RateLimiter::hit($this->throttleKey());
|
|
||||||
$loginField = filter_var($credentials['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'nik';
|
|
||||||
$user = User::where($loginField, $credentials['login'])->first();
|
|
||||||
|
|
||||||
$messages = [];
|
|
||||||
if ($user) {
|
|
||||||
$messages['password'] = 'Password tidak sesuai';
|
|
||||||
} else {
|
|
||||||
$messages['login'] = 'Email/NIK tidak ditemukan';
|
|
||||||
}
|
|
||||||
|
|
||||||
throw ValidationException::withMessages($messages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
"providers": [
|
"providers": [
|
||||||
"Modules\\Authentication\\Providers\\AuthenticationServiceProvider"
|
"Modules\\Authentication\\Providers\\AuthenticationServiceProvider"
|
||||||
],
|
],
|
||||||
"files": [
|
"files": [],
|
||||||
"app/Helpers/uim.php"
|
|
||||||
],
|
|
||||||
"menu": {}
|
"menu": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,89 +3,81 @@
|
|||||||
@push('styles')
|
@push('styles')
|
||||||
<style>
|
<style>
|
||||||
.branded-bg {
|
.branded-bg {
|
||||||
background-image: url('assets/media/images/2600x1600/bg-3.png');
|
background-image:url('assets/media/images/2600x1600/1.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark .branded-bg {
|
.dark .branded-bg {
|
||||||
background-image: url('assets/media/images/2600x1600/bg-3-dark.png');
|
background-image: url('assets/media/images/2600x1600/1-dark.png');
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="grid lg:grid-cols-2 grow">
|
<div class="grid lg:grid-cols-2 grow">
|
||||||
<div class="flex order-2 justify-center items-center p-8 lg:p-10 lg:order-1">
|
<div class="flex justify-center items-center p-8 lg:p-10 order-2 lg:order-1">
|
||||||
<div class="card max-w-[370px] w-full">
|
<div class="card max-w-[370px] w-full">
|
||||||
<form action="{{ route('login') }}" class="flex flex-col gap-5 p-10 card-body" id="sign_in_form" method="POST">
|
<form action="{{ route('login') }}" class="card-body flex flex-col gap-5 p-10" id="sign_in_form" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="mb-2.5 text-center">
|
<div class="text-center mb-2.5">
|
||||||
<h3 class="mb-2.5 text-lg font-semibold leading-none text-gray-900">
|
<h3 class="text-lg font-semibold text-gray-900 leading-none mb-2.5">
|
||||||
Sign in
|
Sign in
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<label class="text-gray-900 form-label">
|
<label class="form-label text-gray-900">
|
||||||
Email or NIK
|
Email or NIK
|
||||||
</label>
|
</label>
|
||||||
<input class="w-full input @error('login') border-danger @enderror"
|
<input class="w-full input @error('login') border-danger @enderror" placeholder="Enter your email or NIK" type="text" name="login" value="{{ old('login') }}">
|
||||||
placeholder="Enter your email or NIK" type="text" name="login" value="{{ old('login') }}">
|
|
||||||
@error('login')
|
@error('login')
|
||||||
<em class="text-sm alert text-danger">{{ $message }}</em>
|
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<div class="flex gap-1 justify-between items-center">
|
<div class="flex items-center justify-between gap-1">
|
||||||
<label class="text-gray-900 form-label">
|
<label class="form-label text-gray-900">
|
||||||
Password
|
Password
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<label class="input" data-toggle-password="true">
|
<label class="input" data-toggle-password="true">
|
||||||
<input class="@error('password') border-danger @enderror" name="password"
|
<input class="@error('password') border-danger @enderror" name="password" placeholder="Enter Password" type="password" value=""/>
|
||||||
placeholder="Enter Password" type="password" value="" />
|
|
||||||
<div class="btn btn-icon" data-toggle-password-trigger="true">
|
<div class="btn btn-icon" data-toggle-password-trigger="true">
|
||||||
<i class="ki-outline ki-eye toggle-password-active:hidden"></i>
|
<i class="ki-outline ki-eye toggle-password-active:hidden"></i>
|
||||||
<i class="hidden ki-outline ki-eye-slash toggle-password-active:block"></i>
|
<i class="ki-outline ki-eye-slash hidden toggle-password-active:block"></i>
|
||||||
</div>
|
</div>
|
||||||
|
@error('password')
|
||||||
|
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||||
|
@enderror
|
||||||
</label>
|
</label>
|
||||||
@error('password')
|
|
||||||
<em class="text-sm alert text-danger">{{ $message }}</em>
|
|
||||||
@enderror
|
|
||||||
</div>
|
</div>
|
||||||
<label class="checkbox-group">
|
<label class="checkbox-group">
|
||||||
<input class="checkbox checkbox-sm" name="check" type="checkbox" value="1" />
|
<input class="checkbox checkbox-sm" name="check" type="checkbox" value="1"/>
|
||||||
<span class="checkbox-label">
|
<span class="checkbox-label">
|
||||||
Remember me
|
Remember me
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<button type="submit" class="flex justify-center btn btn-primary grow">
|
<button type="submit" class="btn btn-primary flex justify-center grow">
|
||||||
Sign In
|
Sign In
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="lg:rounded-xl lg:border lg:border-gray-200 lg:m-5 order-1 lg:order-2 bg-top xxl:bg-center xl:bg-cover bg-no-repeat branded-bg">
|
||||||
class="order-1 bg-top bg-no-repeat lg:rounded-xl lg:border lg:border-gray-200 lg:m-5 lg:order-2 xxl:bg-center xl:bg-cover branded-bg">
|
<div class="flex flex-col p-8 lg:p-16 gap-4">
|
||||||
<div class="flex flex-col gap-4 p-8 w-full lg:p-16">
|
<a href="{{ route('dashboard') }}">
|
||||||
<div class="flex w-full">
|
<img class="h-[100px] max-w-none" src="assets/media/app/logo-agi.png"/>
|
||||||
<img class="h-[100px] lg:h-[200px] max-w-none" src="assets/media/app/logo-agi.png" />
|
</a>
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<h3 class="text-4xl font-semibold text-gray-900">
|
<h3 class="text-2xl font-semibold text-gray-900">
|
||||||
{{ env('APP_NAME', 'Dashboard') }}
|
Secure Access Portal
|
||||||
</h3>
|
</h3>
|
||||||
<div class="text-lg font-medium text-gray-600">
|
<div class="text-base font-medium text-gray-600">
|
||||||
A robust authentication
|
A robust authentication gateway ensuring
|
||||||
@if (env('METHOD_AUTH') == 'uim')
|
<br/>
|
||||||
integrate with <span class="font-semibold text-gray-900">User ID
|
secure
|
||||||
Management</span>
|
<span class="text-gray-900 font-semibold">
|
||||||
@endif
|
efficient user access
|
||||||
gateway ensuring
|
|
||||||
<br />
|
|
||||||
secure efficient user access to the
|
|
||||||
<span class="font-semibold text-gray-900">
|
|
||||||
{{ env('APP_NAME', 'Dashboard') }}
|
|
||||||
</span>
|
</span>
|
||||||
<br />
|
to the LPJ Online
|
||||||
|
<br/>
|
||||||
Dashboard interface.
|
Dashboard interface.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user