Build CoreOrdered learning track

ERP Identity, Access, and Segregation of Duties

Learn Java Large Scale ERP - Part 007

Deep dive into ERP identity, authorization, access scope, segregation of duties, maker-checker, delegated authority, privileged access, and defensible audit evidence in large-scale Java ERP systems.

19 min read3681 words
PrevNext
Lesson 0734 lesson track0718 Build Core
#java#erp#identity#authorization+5 more

Part 007 — ERP Identity, Access, and Segregation of Duties

1. Target Skill Part Ini

Part ini menjawab satu pertanyaan inti:

Bagaimana mendesain authorization ERP yang benar secara bisnis, aman secara teknis, dapat diaudit, dan tetap bisa berubah ketika organisasi, proses, dan regulasi berubah?

Di aplikasi biasa, access control sering dianggap selesai ketika user punya role dan endpoint dilindungi. Di ERP besar, itu tidak cukup. ERP menyimpan dan mengendalikan tindakan yang berdampak pada uang, stok, kewajiban pajak, kontrak, aset, dan bukti legal. Karena itu access control ERP harus menjawab pertanyaan yang lebih granular:

  • siapa aktornya;
  • tindakan apa yang dilakukan;
  • terhadap objek bisnis apa;
  • dalam scope organisasi mana;
  • pada state dokumen apa;
  • dengan limit otorisasi berapa;
  • apakah aktor juga pernah melakukan langkah yang konflik;
  • apakah akses itu normal, delegated, emergency, atau system-generated;
  • bukti keputusan authorization apa yang disimpan.

Dalam kerangka Kaufman, part ini adalah fase learn enough to self-correct untuk security ERP. Targetnya bukan menghafal RBAC/ABAC, tetapi punya model mental untuk melihat desain authorization yang rapuh sebelum masuk production.

2. Mental Model Utama: Actor, Action, Object, Context, Decision, Evidence

Authorization ERP yang matang bisa diringkas menjadi enam elemen:

Jangan mulai dari role. Mulai dari keputusan bisnis.

Contoh:

“Rina boleh approve purchase order senilai IDR 75 juta untuk branch Jakarta karena ia punya role Procurement Manager pada legal entity PT A, limit approval-nya IDR 100 juta, tidak membuat dokumen tersebut, tidak menjadi penerima barang, dan tidak sedang dalam status delegated conflict.”

Keputusan itu tidak bisa diekspresikan dengan hasRole("MANAGER"). Dibutuhkan gabungan:

  • role;
  • scope organisasi;
  • object attribute;
  • document lifecycle;
  • amount threshold;
  • separation of duties;
  • delegation;
  • audit evidence.

3. Mengapa ERP Authorization Lebih Sulit daripada Aplikasi CRUD

ERP punya beberapa karakteristik yang membuat authorization menjadi domain problem, bukan middleware problem.

Karakteristik ERPImplikasi Authorization
Multi-entity organizationRole harus scoped ke tenant, legal entity, branch, cost center, warehouse, atau project.
Dokumen punya lifecycleHak edit, submit, approve, post, cancel, dan reverse berbeda tergantung state.
Ada dampak finansialApproval harus mempertimbangkan amount, currency, budget, tax, dan policy.
Ada SoDUser yang membuat transaksi tidak boleh selalu menjadi approver, poster, payer, atau reconciler.
Ada period lockHak accounting berubah ketika fiscal period sudah ditutup.
Ada integrasiService account bisa membuat transaksi, tetapi tetap harus punya identity, purpose, dan trace.
Ada reporting/export“Read access” bisa lebih berisiko daripada write access karena data massal bisa dieksfiltrasi.
Ada emergency accessBreak-glass harus mungkin, tetapi harus sempit, tercatat, dan direview.

Aturan desain:

Di ERP, authorization adalah bagian dari business invariant. Jangan diperlakukan sebagai dekorasi endpoint.

4. Deconstruct the Skill: Sub-Skill Authorization ERP

Agar bisa dilatih 20 jam secara efektif, pecah skill ini menjadi sub-skill berikut.

Sub-SkillKemampuan yang Harus Dikuasai
Identity modellingMembedakan human user, service account, job account, integration account, delegated actor.
Scope modellingMemodelkan tenant, legal entity, branch, warehouse, cost center, project, dan report scope.
Permission modellingMendesain permission berdasarkan capability/action, bukan nama menu.
Policy evaluationMenghasilkan allow/deny berdasarkan subject, object, action, dan context.
SoD modellingMengidentifikasi konflik role, konflik aktivitas, dan konflik pada objek yang sama.
Approval authorityMenghubungkan approval dengan amount limit, hierarchy, delegation, dan escalation.
Data access controlMenerapkan row-level filtering, field masking, report/export control.
Audit evidenceMenyimpan bukti keputusan authorization, bukan hanya “user clicked approve”.
Privileged accessMendesain emergency access, admin access, service account, dan review.
Test strategyMenguji negative path, bypass attempt, state transition abuse, dan cross-tenant leak.

5. Identity Model: Jangan Semua Aktor Disebut User

ERP besar harus membedakan beberapa jenis actor.

5.1 Human User

Human user adalah aktor yang mewakili manusia. Data minimal:

  • stable identity ID;
  • email/login identifier;
  • employment status;
  • home organization;
  • manager/approval chain jika relevan;
  • assigned roles;
  • delegated rights;
  • last access review status.

Jangan jadikan email sebagai primary key bisnis. Email bisa berubah. Gunakan immutable identity ID.

5.2 Service Account

Service account digunakan oleh sistem eksternal atau internal service. Ini tidak boleh disamakan dengan superuser.

Service account harus punya:

  • owning team;
  • purpose;
  • allowed API scope;
  • allowed data scope;
  • credential rotation policy;
  • rate limit;
  • audit identity;
  • expiry atau review date.

Contoh buruk:

integration-user / password shared / role ADMIN / used by all external systems

Contoh lebih sehat:

actorType: SERVICE_ACCOUNT
name: bank-payment-gateway-prod
purpose: submit bank payment status callback
allowedActions:
  - payment.callback.receive
  - payment.status.update
allowedScopes:
  - tenant = retail-prod
  - legalEntity = PT-A
expiresReviewAt: 2026-12-31

5.3 Batch Job Account

ERP memiliki banyak batch job: close period, aging calculation, stock valuation, MRP, depreciation, statement generation. Semua harus punya identity.

Ketika job membuat journal, audit trail tidak boleh hanya berkata:

created_by = SYSTEM

Lebih baik:

created_by_actor_id = batch:monthly-depreciation
triggered_by = scheduler
approved_by = finance-controller
run_id = jobrun-20260630-001
source_policy = depreciation-policy-v2026.04

5.4 Delegated Actor

Delegation berbeda dari role assignment permanen. Delegation adalah hak sementara yang biasanya muncul karena cuti, assignment proyek, emergency, atau escalation.

Minimal rule delegation:

  • ada principal;
  • ada delegate;
  • ada periode efektif;
  • ada scope;
  • ada action yang didelegasikan;
  • ada batas SoD;
  • ada audit.

Delegation tidak boleh menghapus tanggung jawab principal. Ia menambah konteks keputusan.

6. Authorization Vocabulary yang Harus Konsisten

Gunakan vocabulary eksplisit agar engineer, auditor, product owner, dan security team bicara bahasa yang sama.

IstilahArti
SubjectActor yang meminta akses.
Resource/ObjectObjek bisnis yang diakses, misalnya invoice, PO, journal, report.
ActionOperasi yang diminta, misalnya view, submit, approve, post, reverse, export.
ScopeBatas organisasi/data, misalnya tenant, legal entity, branch, warehouse.
AttributeProperti subject/object/context yang dipakai policy.
PolicyAturan yang mengevaluasi request.
DecisionHasil evaluasi: allow, deny, challenge, escalate.
EvidenceBukti kenapa keputusan diberikan.
ObligationTindakan tambahan setelah allow, misalnya require comment, require MFA, log reason.

7. RBAC, ABAC, ReBAC: Bukan Pilih Salah Satu

7.1 RBAC untuk Stabilitas Administrasi

RBAC cocok untuk menyatakan tanggung jawab organisasi yang relatif stabil:

  • Finance Clerk;
  • Finance Manager;
  • Procurement Officer;
  • Warehouse Supervisor;
  • Inventory Controller;
  • AP Accountant;
  • AR Collector;
  • System Auditor.

RBAC berguna karena role assignment mudah dimengerti oleh user dan auditor. NIST RBAC menekankan role, permission, user assignment, serta constraint seperti separation of duty. Itu relevan untuk ERP karena ERP punya job function dan kontrol internal yang jelas.

Kelemahan RBAC:

  • role explosion;
  • sulit menangani amount threshold;
  • sulit menangani document state;
  • sulit menangani ownership;
  • sulit menangani kondisi temporal;
  • sulit menangani delegated authority.

7.2 ABAC untuk Keputusan Kontekstual

ABAC cocok ketika keputusan bergantung pada attribute:

  • amount <= approvalLimit;
  • legalEntity in actor.allowedLegalEntities;
  • document.branchId in actor.allowedBranches;
  • document.status == SUBMITTED;
  • fiscalPeriod.isOpen == true;
  • actor.department == document.department;
  • environment.riskLevel != HIGH;
  • request.time within businessHours.

NIST SP 800-162 mendefinisikan ABAC sebagai metodologi logical access control yang mengevaluasi attribute subject, object, operation, dan environment terhadap policy. Ini persis kebutuhan ERP untuk keputusan granular.

Kelemahan ABAC:

  • policy bisa sulit dibaca;
  • audit bisa sulit jika reason tidak disimpan;
  • debugging akses menjadi rumit;
  • attribute quality menjadi critical;
  • policy sprawl bisa muncul jika governance lemah.

7.3 ReBAC untuk Relasi Bisnis

Relationship-based access control berguna ketika hak muncul dari relasi:

  • creator boleh edit draft-nya sendiri;
  • manager boleh approve subordinate request;
  • project manager boleh melihat cost project;
  • buyer boleh melihat PO yang berada dalam procurement group-nya;
  • warehouse operator boleh memproses transfer untuk warehouse assignment-nya.

ERP besar biasanya memakai hybrid:

RBAC = apa tanggung jawab formal aktor?
ABAC = apakah kondisi objek/konteks mengizinkan?
ReBAC = apakah aktor punya relasi relevan dengan objek?
SoD = apakah ada konflik tugas?
Workflow = apakah state dan step saat ini mengizinkan?

8. Layer Authorization dalam ERP Java

Authorization harus ada di beberapa layer, tetapi sumber kebenarannya jangan tersebar liar.

LayerTujuanHal yang Tidak Boleh Dilakukan
UIHide/show action untuk usabilityMenjadi satu-satunya enforcement.
API/controllerAuthenticate, coarse authorization, request validationMenyimpan seluruh business policy di annotation endpoint.
Application serviceEnforce use-case permission dan scopeBypass domain policy demi cepat.
Domain policyEnforce invariant, state transition, SoD, approval ruleBergantung pada UI role string.
DatabaseConstraint final, optional row-level securityMenggantikan business authorization yang butuh context.
Reporting/exportPrevent mass data leakageMenganggap read access selalu aman.
AuditSimpan decision evidenceMenyimpan log umum tanpa reason policy.

Spring Security dapat menjadi enforcement framework untuk request/method authorization, tetapi ERP policy tetap harus dimodelkan sebagai domain/application decision, bukan sekadar annotation @PreAuthorize yang menyebar tanpa struktur.

9. Permission Model: Permission Harus Berbasis Capability

Jangan membuat permission dari menu UI:

menu.finance.invoice.button.approve

Itu rapuh karena UI berubah. Gunakan permission berbasis capability/action:

ap.invoice.view
ap.invoice.create
ap.invoice.submit
ap.invoice.approve
ap.invoice.post
ap.invoice.reverse
ap.invoice.export

Permission yang baik punya struktur:

<domain>.<resource>.<action>

Contoh:

DomainResourceAction
procurementpurchase-ordercreate, submit, approve, close, cancel
finance-apvendor-invoicecreate, match, approve, post, reverse, pay
finance-gljournalcreate, approve, post, reverse, close-period
inventorystock-transfercreate, pick, ship, receive, cancel
reportingaging-reportview, export, schedule
adminuser-role-assignmentcreate, revoke, review

Permission bukan keputusan final. Permission adalah input policy.

Contoh:

User has ap.invoice.approve
BUT invoice.amount > user.approvalLimit
=> deny

10. Scope Model: Role Tanpa Scope adalah Bahaya

Role ERP hampir selalu harus scoped.

Contoh role assignment:

ActorRoleScope
RinaAP AccountantPT-A / Jakarta Branch
BudiInventory ControllerPT-A / Warehouse JKT-01
SariFinance ManagerPT-A / All Branches / Cost Center Finance
DimasInternal AuditorTenant retail-prod / read-only / all legal entities

Role Finance Manager tanpa scope bisa berarti terlalu luas:

Finance Manager untuk legal entity mana?
Branch mana?
Cost center mana?
Boleh approve semua currency?
Boleh melihat payroll-adjacent journal?
Boleh close period?

11. Authorization Decision Model dalam Java

Gunakan object eksplisit agar authorization bisa dites, diaudit, dan diperluas.

public enum AccessEffect {
    ALLOW,
    DENY,
    CHALLENGE,
    ESCALATE
}

public record AuthorizationRequest(
        ActorId actorId,
        String action,
        ResourceRef resource,
        OrganizationScope requestedScope,
        Map<String, Object> context,
        Instant requestedAt,
        String correlationId
) {}

public record AuthorizationDecision(
        AccessEffect effect,
        String policyCode,
        String reasonCode,
        String humanReason,
        Map<String, Object> evaluatedAttributes,
        List<String> obligations
) {
    public boolean allowed() {
        return effect == AccessEffect.ALLOW;
    }
}

public interface AuthorizationPolicy {
    boolean supports(AuthorizationRequest request);
    AuthorizationDecision evaluate(AuthorizationRequest request);
}

Contoh penggunaan di application service:

public PurchaseOrderApprovalResult approvePurchaseOrder(
        ApprovePurchaseOrderCommand command,
        ActorId actorId
) {
    PurchaseOrder po = purchaseOrderRepository.getForUpdate(command.purchaseOrderId());

    AuthorizationRequest request = AuthorizationRequestFactory.forResource(
            actorId,
            "procurement.purchase-order.approve",
            ResourceRef.purchaseOrder(po.id()),
            po.organizationScope(),
            Map.of(
                    "amount", po.totalAmount(),
                    "currency", po.currency(),
                    "status", po.status(),
                    "creatorActorId", po.createdBy(),
                    "costCenterId", po.costCenterId()
            )
    );

    AuthorizationDecision decision = authorizationService.decide(request);
    auditAuthorizationDecision(request, decision);

    if (!decision.allowed()) {
        throw new AccessDeniedBusinessException(decision.reasonCode(), decision.humanReason());
    }

    po.approve(actorId, command.comment(), decision.policyCode());
    purchaseOrderRepository.save(po);

    return PurchaseOrderApprovalResult.approved(po.id());
}

Catatan penting:

  • authorization dilakukan setelah object dimuat karena policy butuh attribute object;
  • object dimuat dengan scope aman;
  • decision diaudit;
  • domain method tetap mengecek state transition;
  • policy code disimpan pada approval event.

12. Jangan Menaruh Business Authorization Hanya di Annotation

Annotation seperti @PreAuthorize berguna, tetapi tidak cukup untuk ERP complex authorization.

Contoh terlalu dangkal:

@PreAuthorize("hasRole('FINANCE_MANAGER')")
@PostMapping("/vendor-invoices/{id}/approve")
public ResponseEntity<Void> approve(@PathVariable UUID id) {
    invoiceService.approve(id);
    return ResponseEntity.noContent().build();
}

Masalah:

  • tidak mengecek legal entity;
  • tidak mengecek amount limit;
  • tidak mengecek creator conflict;
  • tidak mengecek status invoice;
  • tidak mengecek fiscal period;
  • tidak mengecek delegated authority;
  • tidak meninggalkan evidence policy.

Lebih baik:

@PostMapping("/vendor-invoices/{id}/approve")
public ResponseEntity<Void> approve(
        @PathVariable UUID id,
        @AuthenticationPrincipal ErpPrincipal principal,
        @RequestBody ApproveInvoiceRequest body
) {
    invoiceApplicationService.approve(
            new ApproveInvoiceCommand(id, body.comment()),
            principal.actorId()
    );
    return ResponseEntity.noContent().build();
}

Lalu business authorization terjadi di application/domain layer.

13. Policy Composition

ERP policy jarang hanya satu rule. Gunakan composition.

Recommended default:

Deny if any mandatory policy denies.
Allow only if required positive policies allow.
Challenge if risk requires step-up.
Escalate if user lacks authority but escalation path exists.

Contoh result:

{
  "effect": "DENY",
  "policyCode": "PO_APPROVAL_POLICY_V3",
  "reasonCode": "SOD_CREATOR_CANNOT_APPROVE",
  "humanReason": "The creator of a purchase order cannot approve the same purchase order.",
  "evaluatedAttributes": {
    "actorId": "usr-102",
    "creatorActorId": "usr-102",
    "purchaseOrderId": "po-9001"
  }
}

14. Separation of Duties: Kontrol, Bukan Formalitas

SoD mencegah satu orang mengendalikan seluruh rantai risiko.

Contoh fraud path tanpa SoD:

Jika satu user bisa melakukan semua, ERP menjadi mesin otomatisasi fraud.

14.1 Jenis SoD

Jenis SoDPenjelasanContoh
Static SoDDua role tidak boleh dimiliki user yang sama.User tidak boleh punya Vendor Maintainer dan Payment Approver.
Dynamic SoDUser boleh punya dua role, tetapi tidak boleh menjalankan keduanya pada transaksi yang sama.Creator invoice tidak boleh approve invoice yang sama.
Object-based SoDKonflik dihitung pada objek atau group objek tertentu.User yang membuat vendor tidak boleh approve invoice untuk vendor itu selama 30 hari.
Temporal SoDKonflik berlaku dalam periode waktu tertentu.User yang menjalankan stock count tidak boleh adjustment untuk item/lokasi yang sama pada hari yang sama.
Workflow SoDStep dalam workflow harus dilakukan aktor berbeda.Submitter dan final approver berbeda.
Cross-domain SoDKonflik melintasi domain.Vendor master maintainer tidak boleh release payment.

14.2 Static SoD Matrix

Role ARole BRisikoPolicy
Vendor MaintainerPayment ReleaserMembuat vendor fiktif dan membayar sendiriMutually exclusive
PO CreatorPO ApproverSelf-approved purchaseDynamic SoD per PO
Goods ReceiverInvoice MatcherFalse receipt + invoice matchRequire independent review
GL Journal CreatorGL Journal PosterUnauthorized accounting entryMaker-checker
User AdminRole ReviewerSelf-provisioning privilegeIndependent access review
Stock CounterStock Adjustment ApproverManipulasi stock varianceDynamic object SoD

14.3 SoD Bukan Hanya Role Assignment

SoD yang hanya dicek saat role diberikan tidak cukup.

Contoh:

Rina punya role PO Creator dan PO Approver.
Itu mungkin diizinkan untuk branch berbeda.
Namun Rina tidak boleh approve PO yang ia buat sendiri.

Jadi SoD harus dicek saat action dilakukan.

public final class CreatorCannotApproveSameDocumentPolicy implements AuthorizationPolicy {

    @Override
    public boolean supports(AuthorizationRequest request) {
        return request.action().equals("procurement.purchase-order.approve");
    }

    @Override
    public AuthorizationDecision evaluate(AuthorizationRequest request) {
        ActorId actorId = request.actorId();
        ActorId creator = (ActorId) request.context().get("creatorActorId");

        if (actorId.equals(creator)) {
            return new AuthorizationDecision(
                    AccessEffect.DENY,
                    "PO_APPROVAL_SOD_V1",
                    "SOD_CREATOR_CANNOT_APPROVE",
                    "Creator cannot approve the same purchase order.",
                    Map.of("actorId", actorId.value(), "creatorActorId", creator.value()),
                    List.of()
            );
        }

        return new AuthorizationDecision(
                AccessEffect.ALLOW,
                "PO_APPROVAL_SOD_V1",
                "SOD_OK",
                "No creator-approver conflict detected.",
                Map.of("actorId", actorId.value()),
                List.of()
        );
    }
}

15. Maker-Checker Pattern

Maker-checker adalah pattern fundamental ERP.

15.1 Invariant Maker-Checker

For controlled action X:
makerActorId != checkerActorId
checker must have authority for action X
checker decision must be recorded with timestamp and policy evidence
object state must be eligible for checking

15.2 Jangan Implementasi Maker-Checker sebagai Boolean

Buruk:

approved = true

Lebih baik:

approval_decision:
  decision_id
  document_id
  step_code
  actor_id
  decision: APPROVED | REJECTED | RETURNED
  decided_at
  comment
  policy_code
  authorization_decision_id

ERP butuh bukti: siapa approve, pada step apa, dengan authority apa, berdasarkan policy apa, dan terhadap state dokumen apa.

16. Approval Authority: Limit, Currency, Hierarchy

Approval authority biasanya bukan role sederhana.

Contoh rule:

Procurement Manager may approve PO up to IDR 100,000,000
for assigned legal entities and branches,
except if user is creator, requester, or goods receiver,
and only when budget check passed.

Model authority:

16.1 Currency Problem

Approval limit harus jelas basis currency-nya.

Pilihan desain:

  1. limit per currency;
  2. limit base currency dengan conversion rate saat submission;
  3. limit base currency dengan rate saat approval;
  4. limit berdasarkan policy treasury.

Jangan biarkan approval engine diam-diam memakai current FX rate tanpa evidence. Simpan rate snapshot jika digunakan untuk decision.

approval_amount_basis:
  document_currency = USD
  document_amount = 8,000
  converted_currency = IDR
  converted_amount = 131,200,000
  fx_rate = 16,400
  fx_rate_source = treasury-daily-rate
  fx_rate_date = 2026-06-30

17. Workflow Authorization

Workflow step tidak otomatis aman hanya karena workflow engine mengatur step.

Untuk setiap transition, cek:

  • apakah actor boleh menjalankan transition itu;
  • apakah actor eligible untuk step saat ini;
  • apakah actor konflik dengan previous step;
  • apakah step sedang delegated;
  • apakah SLA escalation mengubah eligible actor;
  • apakah document state belum berubah oleh proses lain;
  • apakah approval matrix masih valid.
public void transition(
        WorkflowInstanceId workflowId,
        WorkflowAction action,
        ActorId actorId,
        String comment
) {
    WorkflowInstance instance = workflowRepository.getForUpdate(workflowId);
    BusinessDocument document = documentRepository.get(instance.documentRef());

    AuthorizationDecision decision = workflowAuthorizationService.decide(
            actorId,
            action,
            instance,
            document
    );

    auditAuthorizationDecision(decision);

    if (!decision.allowed()) {
        throw new WorkflowAccessDeniedException(decision.reasonCode());
    }

    instance.apply(action, actorId, comment, decision.policyCode());
    workflowRepository.save(instance);
}

18. Data Access Control: Read Access Bisa Lebih Berbahaya daripada Write

Banyak ERP gagal bukan karena user bisa mengubah data, tetapi karena user bisa melihat atau export terlalu banyak data.

Contoh data sensitif:

  • vendor bank account;
  • employee reimbursement;
  • customer credit limit;
  • margin report;
  • inventory valuation;
  • tax identification;
  • audit findings;
  • contract price;
  • payroll-adjacent cost journal.

Read control harus mencakup:

  • row-level scope;
  • field-level masking;
  • report-level permission;
  • export permission;
  • bulk data threshold;
  • purpose logging;
  • watermarking jika perlu;
  • anomaly detection untuk unusual access.

18.1 Query Scoping

Jangan bergantung pada frontend filter.

Buruk:

@GetMapping("/invoices")
public List<InvoiceDto> list(@RequestParam String legalEntityId) {
    return invoiceQueryService.findByLegalEntity(legalEntityId);
}

Lebih baik:

public Page<InvoiceDto> searchInvoices(
        InvoiceSearchCriteria criteria,
        ActorId actorId,
        Pageable pageable
) {
    DataScope scope = authorizationService.visibleDataScope(
            actorId,
            "ap.invoice.view"
    );

    InvoiceSearchCriteria safeCriteria = criteria.constrainedBy(scope);
    return invoiceReadRepository.search(safeCriteria, pageable);
}

18.2 Field Masking

public VendorDto toDto(Vendor vendor, FieldAccessProfile fieldAccess) {
    return new VendorDto(
            vendor.id(),
            vendor.name(),
            fieldAccess.canView("vendor.taxId") ? vendor.taxId() : "***MASKED***",
            fieldAccess.canView("vendor.bankAccount") ? vendor.bankAccount().masked() : null
    );
}

Masking harus terjadi di server side. Jangan mengirim data sensitif ke UI lalu disembunyikan dengan CSS.

19. Report and Export Authorization

Report ERP sering menjadi bypass authorization.

Contoh:

User tidak boleh melihat vendor bank account di screen vendor,
tetapi bisa export report vendor master lengkap ke CSV.

Karena itu report permission harus dibedakan:

vendor.view
vendor.view-sensitive
vendor.export
vendor.export-sensitive
vendor.report.audit

Checklist report control:

  • report punya owner;
  • report punya classification;
  • report punya allowed scope;
  • report punya row-level filter;
  • sensitive columns dimasking;
  • export butuh permission terpisah;
  • large export tercatat sebagai security event;
  • scheduled report tidak mengirim data ke penerima yang tidak eligible;
  • report definition changes diaudit.

20. Privileged Access dan Break-Glass

ERP butuh privileged access untuk incident, tetapi itu tidak boleh menjadi permanent bypass.

20.1 Jenis Privileged Access

JenisKapan DipakaiKontrol Minimal
System adminKonfigurasi teknisTidak otomatis bisa approve/post transaksi bisnis.
Security adminRole assignmentTidak boleh self-approve access.
Data repair operatorKoreksi data terbatasTicket, approval, script hash, audit.
Break-glass userEmergencyTime-bound, reason mandatory, alert, review.
Support impersonationTroubleshootingRead-only by default, consent/policy, full audit.

20.2 Break-Glass Flow

Invariant:

Break-glass access must be time-bound, reason-bound, scope-bound, and review-bound.

21. Access Review and Certification

ERP access tidak cukup diberikan. Ia harus direview.

Access review harus menjawab:

  • siapa punya role apa;
  • untuk scope mana;
  • sejak kapan;
  • kapan terakhir dipakai;
  • siapa approver assignment;
  • apakah role konflik dengan role lain;
  • apakah user sudah pindah organisasi;
  • apakah service account masih punya owner;
  • apakah privileged role pernah dipakai;
  • apakah access masih diperlukan.

Model sederhana:

access_review_campaign:
  campaign_id
  period
  reviewer_actor_id
  scope
  status

access_review_item:
  item_id
  campaign_id
  actor_id
  role_id
  scope_id
  last_used_at
  sod_findings
  reviewer_decision: KEEP | REVOKE | MODIFY | ESCALATE
  reviewer_comment

22. Audit Evidence untuk Authorization

Audit authorization bukan hanya log teknis.

Log lemah:

2026-06-30 10:20:00 user=rina action=approve status=success

Evidence kuat:

{
  "eventType": "AUTHORIZATION_DECISION",
  "decisionId": "authz-20260630-000123",
  "actorId": "usr-rina",
  "action": "procurement.purchase-order.approve",
  "resourceType": "PURCHASE_ORDER",
  "resourceId": "po-9001",
  "effect": "ALLOW",
  "policyCode": "PO_APPROVAL_POLICY_V3",
  "reasonCode": "APPROVAL_LIMIT_OK",
  "scope": {
    "tenant": "retail-prod",
    "legalEntity": "PT-A",
    "branch": "JKT"
  },
  "evaluatedAttributes": {
    "poAmount": "75000000",
    "currency": "IDR",
    "approvalLimit": "100000000",
    "creatorActorId": "usr-bayu",
    "periodOpen": true
  },
  "requestedAt": "2026-06-30T10:20:00Z",
  "correlationId": "req-abc-123"
}

Audit evidence harus immutable secara logical: tidak diedit in-place. Jika perlu koreksi, buat correction event.

23. Caching Authorization: Performa vs Correctness

Authorization ERP bisa mahal karena policy butuh role, scope, hierarchy, delegation, and object attributes. Namun caching berbahaya jika salah.

Aman untuk dicache pendek:

  • role assignment snapshot;
  • organization scope tree;
  • static permission catalog;
  • policy definition version;
  • user profile non-sensitive.

Jangan cache terlalu lama:

  • approval limit setelah role revoked;
  • delegation aktif;
  • emergency access;
  • period lock status;
  • document state;
  • SoD history pada transaksi aktif.

Rule:

Cache permission metadata; re-evaluate object-sensitive decisions at action time.

Gunakan policyVersion dan accessSnapshotVersion untuk audit.

24. Revocation Problem

Ketika akses dicabut, efeknya harus jelas.

Pertanyaan desain:

  • Apakah session aktif langsung invalid?
  • Apakah token lama masih berlaku?
  • Apakah approval task yang sudah assigned harus ditarik?
  • Apakah scheduled report milik user harus dihentikan?
  • Apakah delegated access ikut dicabut?
  • Apakah service account credential harus rotate?

Revocation harus memicu domain events:

RoleAssignmentRevoked
DelegationRevoked
PrivilegedAccessEnded
ApprovalTaskReassigned
ScheduledReportSuspended
ServiceAccountScopeChanged

25. Anti-Pattern Authorization ERP

Anti-PatternGejalaDampak
Role as menuPermission mengikuti UIAPI/report bisa bypass.
Global admin for supportSupport punya akses bisnis penuhFraud dan audit finding.
System user everywhereSemua job menulis sebagai SYSTEMTidak ada accountability.
Approval by role onlyManager bisa approve semuaLimit dan SoD rusak.
No object scopeRole tidak scopedCross-entity data leakage.
Client-side filteringFrontend menyembunyikan dataUser bisa bypass lewat API.
Static SoD onlyKonflik hanya dicek saat role assignmentSelf-approval tetap terjadi.
No decision evidenceHanya log success/failTidak defensible saat audit.
Permanent delegationDelegasi tidak expirePrivilege creep.
Report bypassReport tidak mengikuti policyData sensitif bocor.

26. Testing Strategy

26.1 Test Matrix

Test TypeContoh
Positive authorizationFinance Manager approve invoice dalam limit dan scope.
Negative authorizationFinance Manager approve invoice di legal entity lain.
SoD testCreator mencoba approve dokumen sendiri.
State testUser approve dokumen yang masih draft.
Amount testApprover mencoba approve di atas limit.
Scope testWarehouse user melihat stock warehouse lain.
Delegation testDelegate approve dalam periode efektif.
Revocation testRole dicabut lalu user mencoba action dengan session aktif.
Report testUser export report dengan sensitive columns.
Service account testIntegration account mencoba API di luar scope.

26.2 Example Unit Test

@Test
void creatorCannotApproveOwnPurchaseOrder() {
    ActorId rina = ActorId.of("usr-rina");

    AuthorizationRequest request = new AuthorizationRequest(
            rina,
            "procurement.purchase-order.approve",
            ResourceRef.purchaseOrder("po-1"),
            OrganizationScope.legalEntity("PT-A"),
            Map.of("creatorActorId", rina),
            Instant.parse("2026-06-30T10:00:00Z"),
            "test-correlation"
    );

    AuthorizationDecision decision = policy.evaluate(request);

    assertThat(decision.effect()).isEqualTo(AccessEffect.DENY);
    assertThat(decision.reasonCode()).isEqualTo("SOD_CREATOR_CANNOT_APPROVE");
}

26.3 Property-Based Test Idea

Invariant:

For any controlled document, no actor may perform both maker and checker action on the same document unless policy explicitly marks emergency override and records break-glass evidence.

Generate random workflows and assert invariant.

27. Design Review Checklist

Gunakan checklist ini saat review authorization ERP.

Identity

  • Apakah human, service, batch, dan delegated actor dibedakan?
  • Apakah service account punya owner dan purpose?
  • Apakah SYSTEM tidak dipakai sebagai tempat sampah audit?

Permission

  • Apakah permission berbasis capability/action, bukan menu?
  • Apakah write, approve, post, reverse, export dipisahkan?
  • Apakah report/export punya permission sendiri?

Scope

  • Apakah role assignment scoped ke tenant/legal entity/branch/warehouse/cost center?
  • Apakah query data selalu dibatasi oleh server-side data scope?
  • Apakah cross-tenant leak dites?

SoD

  • Apakah static dan dynamic SoD dipisahkan?
  • Apakah creator/checker conflict dicek pada action time?
  • Apakah cross-domain SoD dipertimbangkan?

Workflow

  • Apakah setiap transition mengecek authorization?
  • Apakah delegation punya effective date dan scope?
  • Apakah escalated task tetap mempertahankan SoD?

Audit

  • Apakah decision reason disimpan?
  • Apakah evaluated attributes penting disimpan?
  • Apakah policy version disimpan?
  • Apakah privileged action direview?

28. 20-Hour Practice Drill

Untuk melatih skill part ini, gunakan latihan berikut.

Drill 1 — Permission Catalog

Ambil domain Procure-to-Pay. Buat permission catalog untuk:

  • requisition;
  • purchase order;
  • goods receipt;
  • vendor invoice;
  • payment proposal;
  • vendor master.

Pastikan action tidak mengikuti nama tombol UI.

Drill 2 — Scope Model

Desain role assignment untuk perusahaan dengan:

  • 1 tenant;
  • 3 legal entity;
  • 12 branch;
  • 4 warehouse;
  • shared procurement center;
  • local finance team.

Tentukan role mana global, mana scoped.

Drill 3 — SoD Matrix

Buat SoD matrix untuk Procure-to-Pay dan Order-to-Cash. Tandai static, dynamic, object-based, dan temporal conflicts.

Drill 4 — Authorization Decision Object

Implementasikan Java interface untuk policy evaluator dan tulis minimal 10 unit test negative path.

Drill 5 — Audit Evidence

Desain event schema untuk authorization decision. Pastikan auditor bisa menjawab: “kenapa transaksi ini boleh disetujui?”

29. Ringkasan

Authorization ERP bukan sekadar login, role, dan endpoint security. ERP membutuhkan authorization yang menyatu dengan domain:

  • actor harus jelas;
  • action harus berbasis capability;
  • object attribute harus dievaluasi;
  • scope organisasi harus eksplisit;
  • document lifecycle harus membatasi action;
  • SoD harus dicek pada role assignment dan action time;
  • approval authority harus mempertimbangkan limit dan context;
  • report/export harus dikontrol;
  • service, batch, delegation, dan break-glass harus punya audit identity;
  • decision evidence harus disimpan.

Mental model yang harus dibawa ke part berikutnya:

Authorization decision is a business fact. Treat it like a first-class domain artifact.

Part berikutnya masuk ke transaction boundary dan invariant. Di sana kita akan melihat bahwa authorization hanyalah satu dari banyak invariant yang harus dijaga ketika ERP menulis ledger, stock, document lifecycle, workflow, dan integration event.

30. Source Notes

Materi ini disusun dengan mengacu pada prinsip umum dan dokumentasi resmi berikut:

  • NIST Role Based Access Control project dan model RBAC, terutama konsep role, permission, hierarchy, dan separation of duty.
  • NIST SP 800-162 tentang Attribute Based Access Control untuk model subject, object, operation, dan environment attributes.
  • OWASP Application Security Verification Standard, khususnya area authentication, access control, secure design, dan verification requirement.
  • Spring Security reference documentation untuk authorization architecture dan method authorization sebagai enforcement mechanism di aplikasi Java/Spring.
  • Praktik umum internal control ERP: maker-checker, access review, privileged access review, SoD matrix, dan audit evidence.
Lesson Recap

You just completed lesson 07 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.