<sect1 id="zend.acl.introduction">
    <title>Pengenalan</title>

    <para>
        Zend_Acl menyediakan implementasi access control list (ACL) untuk manajemen hak akses (privilege).
        Secara umum, sebuah aplikasi dapat menggunakan ACL untuk mengontrol akses terhadap objek-objek
        yang terproteksi oleh objek yang lain.
    </para>

    <para>
        Untuk keperluan dokumentasi ini, berikut istilah-istilah yang perlu anda ketahui,

        <itemizedlist>
            <listitem>
                <para>
                    <emphasis role="strong">resource</emphasis> adalah sebuah objek
                    yang dikontrol akses terhadapnya.
                </para>
            </listitem>
            <listitem>
                <para>
                    <emphasis role="strong">role</emphasis> adalah sebuah objek
                    yang meminta akses ke resource.
                </para>
            </listitem>
        </itemizedlist>

        Dengan kalimat sederhana, <emphasis role="strong">role adalah objek yang meminta akses ke resource tertentu</emphasis>.
        Sebagai ilustrasi, jika pengguna parkir meminta akses ke sebuah mobil, maka pengguna parkir tersebut
        adalah role, sementara mobil adalah resource, karena hak akses ke mobil tertentu tidak dimiliki semua orang.
    </para>

    <para>
        Dengan spesifikasi dan penggunaan ACL, sebuah aplikasi dapat mengontrol
        bagaimana role diberikan hak untuk mengakses resource tertentu.
    </para>

    <sect2 id="zend.acl.introduction.resources">
        <title>Tentang Resource</title>
        <para>
            Membuat sebuah resource di Zend_Acl sangat mudah. Zend_Acl menyediakan interface
            <code>Zend_Acl_Resource_Interface</code> untuk memfasilitasi pembuatan resource dalam sebuah aplikasi.
            Sebuah class hanya perlu mengimplementasikan interface ini, yang terdiri dari hanya sebuah method,
            <code>getResourceId()</code>, dan Zend_Acl akan mengenali objek tersebut sebagai sebuah resource.
            Zend_Acl juga menyediakan <code>Zend_Acl_Resource</code> sebagai implementasi
            dasar dari <code>Zend_Acl_Resource_Interface</code>, sehingga developer cukup meng-extend class
            ini sesuai kebutuhan.
        </para>
        <para>
            Zend_Acl menyediakan struktur pohon untuk menyimpan resource-resource.
            Karena struktur pohon ini, tiap resource dapat diorganisasikan mulai dari
            yang umum (akar) sampai ke yang lebih spesifik (daun). Query pada resource tertentu
            secara otomatis akan mencari aturan-aturan di hirarki resource mulai dari resource
            teratas (ancestor), sehingga dimungkinkan untuk mewariskan aturan
            ke bawahnya dengan lebih mudah.

            Sebagai ilustrasi, jika sebuah role defaultnya diterapkan pada seluruh bangunan di sebuah kota,
            maka akan lebih mudah jika role itu diterapkan terhadap satu kota, bukannya terhadap tiap bangunan
            di dalam kota tersebut. Kalaupun misalnya beberapa bangunan perlu pengecualian, Zend_Acl cukup
            menetapkan pengecualian itu saja ke beberapa gedung. Sebuah resource dapat mewarisi dari
            satu resource yang jadi parent-nya, sementara resource yang jadi parent ini bisa mewarisi
            dari resource di atasnya, dan seterusnya.
        </para>
        <para>
            Zend_Acl juga mendukung hak akses istimewa (privilege) pada resource (mis: "create", "read", "update", "delete"),
            sehingga developer dapat menetapkan aturan yang bisa mempengaruhi seluruh privilege atau sebagian privilege
            saja pada satu atau lebih resource.
        </para>
    </sect2>

    <sect2 id="zend.acl.introduction.roles">
        <title>Tentang Role</title>
        <para>
            Sebagaimana resource, membuat sebuah role juga sangat mudah. Semua role mesti mengimplementasikan
            <code>Zend_Acl_Role_Interface</code>. Interface ini berisi sebuah method, <code>getRoleId()</code>.
            Zend_Acl juga menyediakan <code>Zend_Acl_Role</code> sebagai implementasi dasar dari
            <code>Zend_Acl_Role_Interface</code>, sehingga developer cukup meng-extend class
            ini sesuai kebutuhan.
        </para>
        <para>
            Dalam Zend_Acl, sebuah role dapat mewarisi aturan dari satu atau lebih role di atasnya (parent).
            Sebagai ilustrasi, sebuah role user dengan nama "sally", mungkin milik dari satu atau lebih role
            yang lain yang jadi parent-nya, seperti "editor" dan "administrator" misalnya.
            Developer dapat menetapkan aturan yang berbeda untuk "editor" dan "administrator", dan "sally"
            akan mewarisi aturan tersebut dari keduanya, tanpa harus menetapkan aturan langsung ke "sally".
        </para>
        <para>
            Biarpun kemampuan mewariskan aturan antar role ini sangat berguna, namun terkdang pewarisan
            berlipat (multiple inheritance) ini dapat menimbulkan kompleksitas yang tinggi.
            Contoh berikut memberi ilustrasi masalah pewarisan yang
            menimbulkan kondisi ambiguitas dan bagaimana Zend_Acl memecahkannya.
        </para>
        <example id="zend.acl.introduction.roles.example.multiple_inheritance">
            <title>Multiple Inheritance di antara Role</title>
            <para>
                Kode berikut mendefinisikan tiga role dasar - "<code>guest</code>", "<code>member</code>", dan
                "<code>admin</code>". Kemudian role dengan nama
                "<code>someUser</code>" dibuat dan mewarisi ketiga role tadi. Hati-hati, urutan dimana ketiga role
                parent itu terlihat di array <code>$parents</code> sangat penting.
                Ketika dibutuhkan, Zend_Acl akan mencari aturan akses bukan hanya pada role yang di-query
                (dalam hal ini "<code>someUser</code>"), tapi juga pada role yang mewarisinya (dalam hal ini
                "<code>guest</code>", "<code>member</code>", dan "<code>admin</code>"):
            </para>
            <programlisting role="php"><![CDATA[
$acl = new Zend_Acl();

$acl->addRole(new Zend_Acl_Role('guest'))
    ->addRole(new Zend_Acl_Role('member'))
    ->addRole(new Zend_Acl_Role('admin'));

$parents = array('guest', 'member', 'admin');
$acl->addRole(new Zend_Acl_Role('someUser'), $parents);

$acl->add(new Zend_Acl_Resource('someResource'));

$acl->deny('guest', 'someResource');
$acl->allow('member', 'someResource');

echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';
]]>
            </programlisting>
            <para>
                Karena tidak ada aturan spesifik yang didefinisikan untuk role "<code>someUser</code>" terhadap
                "<code>someResource</code>", Zend_Acl kemudian mencari aturan yang mungkin didefinisikan
                oleh parent dari "<code>someUser</code>". Pertama, Zend_Acl mengunjungi "<code>admin</code>",
                dan ternyata tidak ada aturan untuk resource "<code>someResource</code>" di sini. Selanjutnya,
                Zend_Acl menuju "<code>member</code>", dan Zend_Acl menemukan ada aturan di situ yang menyatakan bahwa
                role "<code>member</code>" diperbolehkan mengakses "<code>someResource</code>".
            </para>
            <para>
                Kalau saja Zend_Acl meneruskan pencariannya ke parent yang lain ("<code>guest</code>"), maka akan
                ditemui bahwa "<code>guest</code>" tidak boleh mengakses "<code>someResource</code>". Ini menimbulkan
                ambiguitas, karena satu role ("<code>someUser</code>") jadi memiliki dua aturan akses yang berlawanan,
                yaitu "allowed" dan "denied".
            </para>
            <para>
                Zend_Acl memecahkan ambiguitas ini dengan menghentikan pencarian ketika sudah ditemukan
                role yang memiliki aturan akses yang ia cari. Dalam kasus ini, karena role "<code>member</code>"
                diperiksa sebelum role "<code>guest</code>", contoh di atas akan mencetak keluaran "<code>allowed</code>".
            </para>
        </example>
        <note>
            <para>
                Ketika anda menetapkan dua role atau lebih sebagai parent dari sebuah role, mesti diingat bahwa
                parent yang terakhir dalam daftar pencarian adalah yang pertama kali ditanya apakah ada aturan
                akses untuk resource yang diminta.
            </para>
        </note>
    </sect2>

    <sect2 id="zend.acl.introduction.creating">
        <title>Membuat Access Control List (ACL)</title>

        <para>
            Sebuah ACL dapat merepresentasikan objek apa saja, baik fisik maupun virtual.
            Namun sebagai demonstrasi, kita akan coba membuat ACL untuk Content Management System (CMS) yang
            mengatur hak akses beberapa pihak terhadap area tertentu. Untuk membuat objek ACL, kita cukup
            inisialisasi ACL dengan tanpa parameter seperti berikut:
        </para>

        <programlisting role="php"><![CDATA[
$acl = new Zend_Acl();
]]>
        </programlisting>

        <note>
            <para>
                Sampai developer menambahkan aturan "allow", Zend_Acl akan menolak ("denied") akses untuk
                setiap privilege dari tiap resource oleh setiap role.
            </para>
        </note>
    </sect2>

    <sect2 id="zend.acl.introduction.role_registry">
        <title>Mendaftarkan Role</title>

        <para>
            CMS hampir selalu membutuhkan hirarki perizinan yang menentukan kemampuan user untuk menambah, mengubah atau
            menghapus content. Umumnya CMS memiliki group 'Guest' yang hanya bisa mengakses demo, group
            'Staff' yang melakukan administrasi harian, group 'Editor' yang bertanggungjawab untuk mem-publish,
            mereview, mengarsip dan menghapus isi tulisan, dan terakhir ada group 'Administrator' yang tugasnya
            mencakup semua tugas group tadi ditambah tugas mengelola informasi-informasi sensitif, manajemen user,
            konfigurasi back-end dan export/backup data.

            Seluruh perizinan ini dapat direpresentasikan dalam sebuah role registry, yang memungkinkan
            tiap group mewarisi hak akses dari group 'parent', sekaligus menyediakan hak akses tertentu
            bagi group mereka sendiri. Perizinan ini dapat diekspresikan sebagai berikut:
        </para>

        <table id="zend.acl.introduction.role_registry.table.example_cms_access_controls">
          <title>Access Control untuk Contoh CMS</title>
          <tgroup cols="3">
            <thead>
              <row>
                <entry>Nama</entry>
                <entry>Hak Akses</entry>
                <entry>Mewarisi Hak Akses Dari</entry>
              </row>
            </thead>
            <tbody>
              <row>
                <entry>Guest</entry>
                <entry>View</entry>
                <entry>N/A</entry>
              </row>
              <row>
                <entry>Staff</entry>
                <entry>Edit, Submit, Revise</entry>
                <entry>Guest</entry>
              </row>
              <row>
                <entry>Editor</entry>
                <entry>Publish, Archive, Delete</entry>
                <entry>Staff</entry>
              </row>
              <row>
                <entry>Administrator</entry>
                <entry>(bisa akses semuanya)</entry>
                <entry>N/A</entry>
              </row>
            </tbody>
          </tgroup>
        </table>

        <para>
            Untuk contoh kasus ini kita akan menggunakan <code>Zend_Acl_Role</code>, walaupun sembarang objek
            yang mengimplementasikan <code>Zend_Acl_Role_Interface</code> bisa digunakan. Group-group ini
            dapat ditambahkan ke role registry dengan cara berikut:
        </para>

        <programlisting role="php"><![CDATA[
$acl = new Zend_Acl();

// Menambahkan group ke Role registry menggunakan Zend_Acl_Role
// Guest tidak mewarisi hak akses dari group lain
$roleGuest = new Zend_Acl_Role('guest');
$acl->addRole($roleGuest);

// Staff mewarisi hak akses dari guest
$acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);

/*
Alternatif lain untuk kode di atas adalah seperti berikut:
$acl->addRole(new Zend_Acl_Role('staff'), 'guest');
*/

// Editor mewarisi hak akses dari staff
$acl->addRole(new Zend_Acl_Role('editor'), 'staff');

// Administrator tidak mewarisi hak akses dari group lain
$acl->addRole(new Zend_Acl_Role('administrator'));
]]>
        </programlisting>

    </sect2>

    <sect2 id="zend.acl.introduction.defining">
        <title>Mendefinisikan Access Control</title>

        <para>
            Sekarang di dalam ACL sudah ada role-role, berikutnya kita dapat menentukan bagaimana aturan akses tiap role
            tersebut ke resource. Kalau anda perhatikan, kita belum mendefinsikan satupun resource
            dalam contoh kasus ini. Yang sederhananya ini berarti semua aturan berlaku untuk semua resource, apapun itu.
            Ini karena Zend_Acl menerapkan aturan akses dari yang umum ke yang lebih spesifik
            dengan tujuan untuk meminimasi jumlah aturan yang mesti dibuat. Ini dimungkinkan karena resource dan role mewarisi
            aturan yang didefinisikan di pendahulu-pendahulu mereka sebelumnya.
        </para>

        <note>
            <para>
                Secara umum, Zend_Acl mematuhi aturan tertentu jika dan hanya jika tidak ada aturan lain
                yang lebih spesifik.
            </para>
        </note>

        <para>
            Sebagai konsekuensi hal ini, kita dapat mendefinisikan seperangkat aturan yang kompleks dengan
            kode yang minimal. Untuk contoh kasus kita di atas, berikut adalah kode untuk menerapkan aturan aksesnya:
        </para>

        <programlisting role="php"><![CDATA[
$acl = new Zend_Acl();

$roleGuest = new Zend_Acl_Role('guest');
$acl->addRole($roleGuest);
$acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
$acl->addRole(new Zend_Acl_Role('editor'), 'staff');
$acl->addRole(new Zend_Acl_Role('administrator'));

// Guest hanya boleh melihat (view) content
$acl->allow($roleGuest, null, 'view');

/*
Kode di atas bisa juga ditulis:
$acl->allow('guest', null, 'view');
//*/

// Staff mewarisi hak akses view dari guest, tapi juga perlu tambahan izin revise
$acl->allow('staff', null, array('edit', 'submit', 'revise'));

// Editor mewarisi izin view, edit, submit, dan revise dari
// staff, tapi juga perlu tambahan izin delete
$acl->allow('editor', null, array('publish', 'archive', 'delete'));

// Administrator tidak mewarisi apa-apa, tapi memiliki semua hak akses
$acl->allow('administrator');
]]>
        </programlisting>

        <para>
            Nilai <code>null</code> dalam method <code>allow()</code> di atas digunakan untuk
            mengindikasikan kalau aturan bersangkutan berlaku untuk semua resource.
        </para>

    </sect2>

    <sect2 id="zend.acl.introduction.querying">
        <title>Mengambil (Query) Aturan ACL</title>

        <para>
            Sekarang kita sudah memiliki ACL yang fleksibel yang dapat digunakan untuk menentukan apakah
            pemohon memiliki akses untuk melakukan fungsi tertentu dalam sebuah aplikasi web.
            Untuk mengambil (query) aturan ACL yang telah ditetapkan sebelumnya cukup dengan menggunakan
            method <code>isAllowed()</code> seperti berikut:
        </para>

        <programlisting role="php"><![CDATA[
echo $acl->isAllowed('guest', null, 'view') ?
     "allowed" : "denied";
// allowed

echo $acl->isAllowed('staff', null, 'publish') ?
     "allowed" : "denied";
// denied

echo $acl->isAllowed('staff', null, 'revise') ?
     "allowed" : "denied";
// allowed

echo $acl->isAllowed('editor', null, 'view') ?
     "allowed" : "denied";
// allowed karena mewarisinya dari guest

echo $acl->isAllowed('editor', null, 'update') ?
     "allowed" : "denied";
// denied karena tidak ada aturan allow untuk 'update'

echo $acl->isAllowed('administrator', null, 'view') ?
     "allowed" : "denied";
// allowed karena administrator diperbolehkan mengakses apapun

echo $acl->isAllowed('administrator') ?
     "allowed" : "denied";
// allowed karena administrator diperbolehkan mengakses apapun

echo $acl->isAllowed('administrator', null, 'update') ?
     "allowed" : "denied";
// allowed karena administrator diperbolehkan mengakses apapun
]]>
        </programlisting>

    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
