Users dan Privilege (kontrol akses)
Area: sistem, kontrol akses, lintas modul.
Cara halaman ini diverifikasi
Fungsi privilege, tabel resource, LDAP dan backdoor login dikonfirmasi di Medco pada Juni 2026. Pada 2026-09-06 fungsi pemeriksaan, backdoor, LDAP, daftar organisasi, helper operator-role dan tipe action privilege diperiksa ulang di master dan big five.
Ringkasan
INACT mempertahankan pengguna (ts_org_person) dan grup (ts_group_user), tetapi lapisan privilege-nya adalah model berbasis resource per project. Bukan "grup ke privilege", aksesnya adalah:
User ─┬─ group_id (ts_group_user) ← masih ada, dipakai untuk pemeriksaan admin dan peran
└─ adalah RESOURCE di sebuah project (ts_resource)
└─ milik RESOURCE GROUP (ts_resource_group, lewat ts_map_resource_group)
└─ PRIVILEGE melekat ke resource group
(ts_privileges_resource: resource-group × modul × action)Akibat praktisnya: seorang pengguna bisa punya privilege berbeda di project berbeda, karena privilege menggantung pada resource group tempat mereka berada per project, bukan pada satu grup pengguna global. Model ini, dan migrasi ts_privileges_resource di baliknya, ada di kelima fork.
Pengguna
Tabel ts_org_person. Kolom utama: person_no (PK), person_id (login), person_password (MD5), group_id, person_active, person_project_code (CSV project), plus person_ldap_id (tautan LDAP, di tempat LDAP ada) dan last_activity (logout otomatis). Dikelola di modules/member/ dan halaman setup registrasi.
Autentikasi dan sesi
- Lokal dulu. Login mencoba
person_idlokal plusmd5(password)terhadapts_org_persondimember_login.inc.php. - Cadangan LDAP, hanya master dan Medco. Kalau tidak ditemukan dan
enable_ldap_login='1', ia melakukan bindperson_id@<domain>ke direktori dan, saat berhasil, memakai barists_org_personyang cocok yang ditautkan lewatperson_ldap_id. Setting koneksi LDAP ada di tabelinweb_ldap, di-seed olehDefaultInwebLdap.php:host,port,domain,dndasar,usernamedanpasswordlayanan; pemetaan atribut dildap_attribute_mappings. Flagenable_ldap_logindanenable_ldap_browse, lihat inweb_config. Jadestone, JOTRE dan Timas tidak punya kode LDAP di login dan tidak punya seedinweb_ldap. - Single Session, hanya master dan JOTRE. Dengan
enable_last_login_wins, login baru menulisperson_session_tokendan sesi lama digantikan (iw_is_session_superseded()). Tidak ada di Jadestone, Medco atau Timas, baik di kode maupun di tabel config.
Backdoor impersonasi, di kelima fork
Kalau password yang dikirim mengandung deepbluesea, string dipecah pada kata itu dan super-admin bisa login sebagai pengguna mana pun dengan memberikan <targetUser> plus deepbluesea plus <password super-admin>. Sensitif secara keamanan. Dokumentasikan dan tinjau.
- Password MD5, tanpa salt. Masih lemah.
- Sesi:
$_SESSION['inactmemberkey'](person_id plus password terenkripsi, pemisahMY_CODE) dan cookieINACTSESSID<md5(baseurl)>. Global request:$_LOGIN_ID,$_LOGIN_GROUP_ID, dan$_LOGIN_GROUP_RESOURCE, id resource group yang menggerakkan pemeriksaan privilege. Logout otomatis lewatauto_logout.phpsaatenable_auto_logout='1'(idle lebih lama dariauto_logout_defaultmenit), dilacak dits_org_person.last_activity.
Grup dan peran
Tabel ts_group_user: group_code unik, group_desc. group_id pada pengguna masih dipakai untuk pemeriksaan grup admin dan logika peran, tetapi bukan lagi tempat privilege fitur disimpan. Itu pindah ke resource group.
Model resource
| Tabel | Berisi |
|---|---|
ts_resource | seseorang yang terdaftar sebagai resource di sebuah project (person_no, project_id, resource_group_id, resource_active, organization_name, lihat di bawah) |
ts_resource_group | sebuah resource group di dalam project (resource_group_id, resource_group_name, project_id) |
ts_map_resource_group | memetakan resource, resource group dan project |
ts_privileges_resource | registri privilege: group_resource_id × modules_code × modules_priv × priv_type |
Seorang pengguna ditetapkan sebagai resource di setiap project yang dikerjakannya, ditempatkan di sebuah resource group, dan baris ts_privileges_resource grup itulah yang menentukan apa yang boleh mereka lakukan di project itu. Keanggotaannya diedit di Users & Privileges > Group Resource, di jendela Set Member of Group Resource (modules/reference/resource_group.php, cmd=listresource, template resource_group_browse.htm): dua daftar, tersedia dan anggota, masing-masing dengan kotak quicksearch yang mencocokkan teks option. Di master sebuah option terbaca Resource Name (person_id), jadi pencarian hanya menemukan resource dan id; Jadestone menambah nama person, lihat perbedaan antar instance.



Panel Resource Group adalah iframe (modref=resource_group&page_as_content_only=1) yang membaca project dari select multi_reference_project di halaman induk. Di checkout Jadestone lokal panel ini kadang dimuat sebelum select itu terisi, melempar Cannot read properties of null (reading 'value') di loadResource(), dan berputar terus; memuat ulang frame-nya memperbaiki. Perlu dicek di produksi sebelum menganggapnya artefak lokal.
Project Organization
Di Reference, Resource, setiap baris resource punya kolom "Project Organization" (modules/reference/resource.php). Ia mencatat sisi project mana yang diwakili orang itu: sisi owner / internal project, atau pihak luar. Diset per resource, per project, terlepas dari resource group yang memberi privilege.
Apa itu
Kolom string bebas di
ts_resource, dibatasi di UI ke daftar tetap,$LIST_ORGANIZATION, diadditional_global_variables.inc.php. Identik di kelima fork:php$LIST_ORGANIZATION = array("Main Company", "Third Party"); // sebelumnya (dikomentari): array("Contractor", "Company", "Vendor", "Partner");Jadi hari ini praktis ia flag dua arah internal / eksternal: Main Company (project owner) atau Third Party (kontraktor, klien, vendor). Label tampilannya mengikuti config: sisi utama menampilkan
project_company_internal_label(default "Main Company"), sisi lain menampilkanproject_company_external_label(default "Third Party"), lihat inweb_config. Default label ini sama dengan nilai$LIST_ORGANIZATION, jadi keduanya tetap sinkron.Diset di UI lewat tautan Set di grid Resource (
showListOrganization,cmd=listorganization, opsi dari$LIST_ORGANIZATION), atau saat menambah atau mengedit resource.Default: seed
DefaultTsResource.phpmengeset"Main Company". Skrip RBAC SQL Server Medco,migrations/scripts/MIG-010_rbac_seed.php, mengisinyaNULL.
Kapan dipakai
Satu-satunya tempat ia aktif mengubah perilaku adalah form sign-off / response (routing_resp.htm), yang membaca organisasi responder sebagai {resource_organization_name}, diset di routing.php. Di master, Jadestone dan Medco dua cabangnya relatif terhadap owner: form menerima {organization_name_owner} dan {organization_name_non_owner}, diselesaikan per deployment dari inact_operator_role, lihat siapa yang mengoperasikan INACT.
- Cabang non-owner: menyembunyikan Next Expected untuk sisi yang bukan project owner. Responder approval-type non-owner mendapat Next Expected tersembunyi.
- Cabang owner: menyembunyikan Next Expected untuk sisi owner pada
D/C/S/L, setiap action Approval-type selain Approval:if (!['Approval'].includes(a) && "{resource_organization_name}" == "{organization_name_owner}"). Jadi Transmit, Checking, Responsible dan Leader milik project owner kehilangan Next Expected, tetapiApproval(A) milik owner mempertahankannya. Digabung dengan penyembunyian non-owner, hasil akhirnya Next Expected hanya tampil untukApprovalmilik project owner, lihat Sign Off, kesimpulan Next Expected. Dengan defaultinact_operator_role = contractorowner-nya adalah sisi Third-Party, jadi ini mereproduksi perilaku historis "hanya tampil untuk Approver Third-Party".
JOTRE dan Timas meng-hard-code sisinya
routing_resp.htm mereka membandingkan {resource_organization_name} dengan literal 'Third Party'. Tidak ada key inact_operator_role dan tidak ada helper label owner di kedua fork itu.
Siapa yang mengoperasikan INACT (inact_operator_role)
Config seluruh deployment inact_operator_role (company | contractor, default contractor) mencatat pihak dunia nyata mana yang mengoperasikan instance INACT ini: project owner migas ("Company" dalam bahasa Document Controller) atau kontraktor atau vendor atas namanya. Ia adalah satu-satunya sumber kebenaran untuk "sisi Project Organization mana yang menjadi project owner", diselesaikan oleh helper getProjectOwnerOrgLabel(), getProjectNonOwnerOrgLabel() dan isInactOperatedByCompany() di reference_function.inc.php. Ada di master, Jadestone dan Medco.
inact_operator_role | Operator melabeli dirinya | Project owner = | Next Expected tampil untuk |
|---|---|---|---|
contractor (default) | Main Company (internal) | Third Party (eksternal) | Approver Third-Party, perilaku historis |
company | Main Company (internal) | Main Company (internal) | Approver Main-Company |
Perilaku perspektif operator di masa depan sebaiknya membaca helper ini alih-alih meng-hard-code "Main Company" atau "Third Party".
Organisasi juga disimpan, diedit dan ditampilkan di Reference, Resource, ditampilkan sebagai kolom di pemilih resource Purchase Order, dan daftar resource routing bisa difilter berdasarkannya (routing_group_user.htm mengirim &organization_name= ke routing_handler_ajax.php).
Untuk apa ia tidak dipakai, meski terlihat begitu. Ini mati atau dikomentari:
- Filter return code.
$filterResultCodeyang diturunkan dari organisasi dirouting.phpdihitung dan tidak pernah dibaca. Filter visibilitas return code yang sebenarnya memakai kolom berbeda dengan nama yang membingungkan,ts_doc_resultcode.doc_res_organization, yang berisi CSV peran action routing (setiap action approval-type:"Approval,Checking,Leader,Responsible,Transmit"), dicocokkan dengan action routing, bukan organisasi resource. - Penentuan kontraktor / klien transmittal.
getLastApproverResource()ada dirouting_handler_transmittal.class.phptetapi setiap tempat pemanggilannya dikomentari. - Durasi review berdasarkan organisasi. Pemanggilan
getReviewDurationBasedOnLevel(...)dikomentari dirouting_handler_ajax.php.
Singkatnya: Resource Group menjawab "apa yang boleh dilakukan orang ini?" (privilege); Project Organization menjawab "di pihak siapa mereka?" (Main Company atau Third Party). Praktiknya klasifikasi itu hari ini terutama menangkap dan menampilkan sisinya dan menjaga field Next Expected Submission saat sign-off. Logika routing dan transmittal yang lebih kaya yang dulu dimaksudkan untuk digerakkannya saat ini adalah kode mati.
Keselarasan label dan nilai. Nilainya ada di $LIST_ORGANIZATION (Main Company / Third Party), dan config label tampilan default ke dua string yang sama, jadi perbandingan "main entity" di sign-off bekerja sebagaimana dimaksud. Jaga tetap sinkron: kalau kamu mengganti nama salah satunya, perbarui keduanya, label dan nilai organization_name yang tersimpan, atau perbandingannya rusak. Ini string biasa tanpa foreign key, jadi nilainya tetap bisa menyimpang.
Masalah yang diketahui: label tampilan masuk ke logika routing
project_company_internal_label / project_company_external_label dimaksudkan hanya sebagai label tampilan, tetapi bocor ke logika bisnis: routing.php menyelesaikannya, lewat inact_operator_role, menjadi organization_name_owner / organization_name_non_owner, dan form sign-off bercabang berdasarkan itu. Pilihan sisi mana yang menjadi owner sekarang keputusan eksplisit yang bisa dikonfigurasi, tetapi perbandingannya masih pencocokan string biasa terhadap keterangan yang bisa diedit admin dan diterjemahkan, jadi kerapuhannya tetap ada. Nilai organization_name yang NULL atau diganti nama tidak cocok dengan sisi mana pun.
| Tempat | Yang dikontrol perbandingan label | Tingkat |
|---|---|---|
routing.php | menyelesaikan label owner / non-owner menjadi organization_name_owner / organization_name_non_owner | kebocorannya |
routing_resp.htm, blok Next Expected | menyembunyikan Next Expected Submission | sedang |
routing_resp.htm, blok tombol | mengaktifkan tombol Sign Off / Return | tinggi |
routing_resp.htm, cabang next-expected terisi | mengaktifkan tombol Sign Off / Return | tinggi |
ref_resource_browse.htm | mengeset organization_name default resource baru ke string label, jadi keterangan disimpan ke kolom data ts_resource.organization_name | tinggi (data) |
Kenapa salah: label internal adalah keterangan yang bisa diedit admin dan diterjemahkan. Mencabangkan logika alur kerja, terutama pengaktifan Sign Off versus Return, pada string tampilan berarti mengganti nama atau menerjemahkan label diam-diam merusak gating-nya: tombol yang salah aktif, field yang salah tampil. Ini hanya bekerja hari ini karena default label kebetulan sama dengan nilai $LIST_ORGANIZATION "Main Company".
Perilaku yang dimaksud: label seharusnya hanya tampilan. Logika seharusnya membandingkan pada identitas yang stabil (kode sisi org yang tetap, atau konstanta $LIST_ORGANIZATION[0], bukan keterangan), dan default resource seharusnya menyimpan nilai stabil itu, bukan label. Didokumentasikan sebagai masalah yang diketahui; perbaikannya butuh work item sendiri.
Privilege, pemeriksaan inti
havePrivilegesResource($groupid, $modules, $action) di tracking_function.inc.php meng-query ts_privileges_resource di mana group_resource_id = <$_LOGIN_GROUP_RESOURCE>, modules_code cocok (array menjadi IN), modules_priv = <action>, dan priv_type='module'. Grup kosong berarti izinkan (cadangan); modul reference punya kelonggaran khusus yang digerakkan config.
- Tipe action:
view,add,edit,delete, plus tambahan yang ditawarkan layar privilege per fork: masterupload(documents_master) danready_to_return(routing); Medco jugaarchive(documents); JOTRE hanyaupload; Timas tidak ada tambahan. - Tipe privilege (
priv_type):module,report, dandashboard. Kelima fork menawarkandashboard. - Jalan pintas admin: pemeriksaan ditulis
($_LOGIN_GROUP_ID == 'admin' || havePrivilegesResource(...)), jadi grupadminmelewati pencarian resource. - Legacy hidup berdampingan.
havePrivileges()berbasis grup yang lama dan tabelts_privilegesmasih ada di kelima fork (hibrida). Pastikan mana yang dipakai sebuah layar.
UI admin: modules/reference/group_privileges.php, dan registration/setup_privileges_modules.php, merender grid resource group × modul dengan checkbox per action, menulis ts_privileges_resource.
Registri modul dan resource
Modul ada di ts_modules (modules_code, modules_is_installed), dan sub-referensinya di konstanta MODULE_REFERENCE di src/basic/Base.php. getModuleList() menggerakkan menu; modul yang tidak terpasang dikecualikan sepenuhnya, jadi menu bersifat per instalasi, di atas gating per peran dan per privilege.
Gating menu dan UI, tiga lapis
_menu.php menjaga setiap item lewat, berurutan:
- Super-admin.
inact_super_admin(config) melihat semuanya; item yang terdaftar di$PAGE_TYPE_ONLOADED_AS['accessible_only_by_super_admin']disembunyikan dari semua orang lain. - Grup admin. Item di
accessible_only_by_admin(misalnyausers_privileges) hanya tampil untukgroup_id == 'admin'. - Privilege resource. Selain itu
havePrivilegesResource($_LOGIN_GROUP_RESOURCE, <module>, 'view').
Tombol toolbar di dalam modul dijaga dengan cara yang sama, misalnya ... || havePrivilegesResource($_LOGIN_GROUP_RESOURCE, $mod_code, 'edit').
Super-admin
Dua tingkat: orang config inact_super_admin (satu id developer, default [email protected]) melewati semua gating dan membuka layar dev dan config; grup admin melewati pemeriksaan privilege resource dan layar khusus admin. Lihat inweb_config.
Tabel database
| Tabel | Berisi |
|---|---|
ts_org_person | pengguna (plus person_ldap_id, last_activity) |
ts_group_user | grup |
ts_resource, ts_resource_group, ts_map_resource_group | model resource per project |
ts_privileges_resource | pemberian resource-group × modul × action |
ts_privileges | pemberian grup legacy, masih ada |
ts_modules | registri modul (modules_is_installed) |
inweb_ldap, ldap_attribute_mappings | config LDAP, master dan Medco |
Hal yang perlu diwaspadai
- Password MD5 tanpa salt. Masih lemah.
- Backdoor impersonasi ada di setiap fork. Tinjauan keamanan layak dilakukan.
- Kode privilege hibrida.
havePrivileges/ts_privileges(legacy) danhavePrivilegesResource/ts_privileges_resource(saat ini) hidup berdampingan. Pastikan mana yang dipakai sebuah layar sebelum mengubah pemberian. - SQL tanpa parameter di pemeriksaan privilege (
group_*,modules_code,actiondisisipkan sebagai string). Rawan injection. - Resource group kosong berarti izinkan.
havePrivilegesResource()mengembalikantruesaat$groupidkosong. Resource group yang salah konfigurasi atau belum ditetapkan bisa memberi izin berlebih.
Perbedaan antar instance
Diperiksa pada 2026-09-06.
| Instance | Perbedaan |
|---|---|
| Jadestone | Tanpa LDAP, tanpa Single Session. Punya helper inact_operator_role. Layar privilege menawarkan upload, ready_to_return, dashboard. INA27-244 (Done): jendela Set Member of Group Resource mendaftar Resource Name - Person Name (person_id) dan quicksearch-nya juga mencocokkan nama person, karena id di Jadestone berupa alamat email; resource tanpa person tetap terbaca (No user). |
| Medco | Punya LDAP dan seed inweb_ldap. Tanpa Single Session. Menambah tipe action archive. Membawa skrip MIG-010_rbac_seed.php yang mengisi organization_name NULL di SQL Server. |
| JOTRE | Tanpa LDAP. Punya Single Session (person_session_token). Tanpa inact_operator_role; form sign-off meng-hard-code 'Third Party'. Layar privilege hanya menawarkan upload dan dashboard. |
| Timas | Tanpa LDAP, tanpa Single Session, tanpa inact_operator_role, 'Third Party' hard-coded. Layar privilege hanya menawarkan dashboard. |
Terkait
- inweb_config:
inact_super_admin,enable_ldap_*,enable_last_login_wins,enable_auto_logoutdan gerbang editor config. - Sign Off: tempat Project Organization mengubah perilaku.