Menggunakan cakupan OAuth2

Halaman ini berlaku untuk Apigee dan Apigee Hybrid.

Baca dokumentasi Apigee Edge.

Topik ini membahas cara menggunakan dan menerapkan cakupan OAuth 2.0 dengan Apigee.

Apa itu cakupan OAuth2?

Cakupan OAuth 2.0 memberikan cara untuk membatasi jumlah akses yang diberikan ke sebuah token akses. Misalnya, token akses yang dikeluarkan ke aplikasi klien dapat diberi akses BACA dan TULIS ke resource yang dilindungi, atau hanya akses BACA. Anda dapat menerapkan API untuk menerapkan cakupan atau kombinasi cakupan apa pun yang diinginkan. Jadi, jika klien menerima token yang memiliki cakupan BACA, dan mencoba memanggil endpoint API yang memerlukan akses TULIS, panggilan akan gagal.

Dalam topik ini, kita akan membahas bagaimana cakupan ditetapkan untuk token akses dan cara Apigee menerapkan cakupan OAuth 2.0. Setelah membaca topik ini, Anda akan dapat menggunakan cakupan dengan percaya diri.

Bagaimana cakupan ditetapkan ke token akses?

Saat membuat token akses, Apigee dapat menetapkan cakupan ke token tersebut. Untuk memahami cara kerjanya, Anda harus terlebih dahulu memahami entity Apigee ini: produk API, developer, dan aplikasi developer. Untuk pendahuluan, lihat Pengantar publikasi. Sebaiknya Anda meninjau materi ini jika diperlukan sebelum melanjutkan.

Token akses adalah string panjang berisi karakter yang tampak acak, yang memungkinkan Apigee memverifikasi permintaan API yang masuk (anggap saja ini sebagai pengganti kredensial nama pengguna/sandi pada umumnya). Secara teknis, token adalah kunci yang mengacu pada kumpulan metadata yang terlihat seperti ini:

{
  "issued_at" : "1416962591727",
  "application_name" : "0d3e1d41-a59f-4d74-957e-d4e3275d4781",
  "scope" : "A",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-bs0cSuqS9y]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-AdBmANhsag@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "eTtB7w5lvk3DnOZNGReBlvGvIAeAywun",
  "access_token" : "ODm47ris5AlEty8TDc1itwYPe5MW",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

Metadata token mencakup string token akses yang sebenarnya, informasi masa berlaku, identifikasi aplikasi developer, developer, dan produk yang terkait dengan token. Anda juga akan melihat bahwa metadata tersebut juga menyertakan "cakupan".

Bagaimana token mendapatkan cakupannya?

Kunci pertama untuk memahami cakupan adalah mengingat bahwa setiap produk di aplikasi developer dapat memiliki nol atau beberapa cakupan yang ditetapkan padanya. Cakupan ini dapat ditetapkan ketika produk dibuat, atau dapat ditambahkan nanti. Nama tersebut tersedia sebagai daftar nama dan disertakan dalam "metadata" yang terkait dengan setiap produk.

Saat Anda membuat aplikasi developer dan menambahkan produk ke dalamnya, Apigee melihat semua produk dalam aplikasi developer dan membuat daftar semua cakupan untuk produk tersebut (daftar cakupan global atau master aplikasi -- gabungan dari semua cakupan yang dikenali).

Saat aplikasi klien meminta token akses dari Apigee, aplikasi tersebut dapat secara opsional menentukan cakupan mana yang ingin dikaitkan dengan token tersebut. Misalnya, permintaan berikut meminta cakupan "A". Artinya, klien meminta server otorisasi (Apigee) membuat token akses yang memiliki cakupan "A" (memberikan otorisasi aplikasi untuk memanggil API yang memiliki cakupan "A"). Aplikasi mengirim permintaan POST seperti ini:

curl -i -X POST -H Authorization: Basic Mg12YTk2UkEIyIBCrtro1QpIG \
  -H content-type:application/x-www-form-urlencoded \
  https://apitest.acme.com/oauth/token?grant_type=client_credentials&scope=A

Apa yang terjadi?

Saat menerima permintaan ini, Apigee akan mengetahui aplikasi yang membuat permintaan dan mengetahui aplikasi developer mana yang didaftarkan klien (client ID dan kunci rahasia klien dienkode dalam header autentikasi dasar). Karena parameter kueri scope disertakan, Apigee harus memutuskan apakah ada produk API yang terkait dengan aplikasi developer yang memiliki cakupan "A". Jika ya, token akses akan dibuat dengan cakupan "A". Cara lain untuk melihat ini adalah parameter kueri cakupannya adalah semacam filter. Jika aplikasi developer mengenali cakupan "A, B, X", dan parameter kueri menentukan "scope=X Y Z", hanya cakupan "X" yang akan ditetapkan ke token.

Bagaimana jika klien tidak melampirkan parameter cakupan? Dalam hal ini, Apigee menghasilkan token yang mencakup semua cakupan yang dikenali oleh aplikasi developer. Penting untuk dipahami bahwa perilaku default-nya adalah menampilkan token akses yang berisi gabungan semua cakupan untuk semua produk yang disertakan dalam aplikasi developer.

Jika tidak ada produk yang terkait dengan aplikasi developer yang menentukan cakupan, dan token memiliki cakupan, panggilan yang dilakukan dengan token tersebut akan gagal.

Misalkan suatu aplikasi developer mengenali cakupan ini: A B C D. Ini adalah daftar utama cakupan aplikasi. Mungkin satu produk dalam aplikasi memiliki cakupan A dan B, dan produk kedua memiliki cakupan C dan D, atau kombinasi apa pun. Jika klien tidak menentukan parameter scope (atau jika klien menentukan parameter cakupan tanpa nilai), token akan diberi keempat cakupan: A, B, C, dan D. Sekali lagi, token ini menerima sekumpulan cakupan yang merupakan gabungan dari semua cakupan yang dikenali oleh aplikasi developer.

Ada satu kasus lagi saat perilaku default adalah menampilkan token akses dengan semua cakupan yang dikenali, yaitu saat kebijakan GenerateAccessToken (kebijakan Apigee yang menghasilkan token akses) tidak menentukan elemen <Scope>. Misalnya, berikut adalah kebijakan GenerateAccessToken tempat <Scope> ditentukan. Jika elemen <Scope> tidak ada (atau jika elemen tersebut ada tetapi kosong), perilaku default akan dieksekusi.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-GenerateAccessToken">
    <DisplayName>OAuthV2 - Generate Access Token</DisplayName>
    <Attributes>
      <Attribute name='hello' ref='system.time' display='false'>value1</Attribute>
    </Attributes>
    <Scope>request.queryparam.scope</Scope> 
    <GrantType>request.formparam.grant_type</GrantType>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>GenerateAccessToken</Operation>
    <SupportedGrantTypes>
      <GrantType>client_credentials</GrantType>
    </SupportedGrantTypes>
  <GenerateResponse enabled="true"/>
</OAuthV2>

Bagaimana cakupan diberlakukan?

Pertama-tama, ingat bahwa di Apigee, token akses divalidasi dengan kebijakan OAuthV2 (biasanya ditempatkan di awal alur proxy). Kebijakan harus memiliki operasi VerifyAccessToken yang ditentukan. Mari kita lihat kebijakan ini:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope> <!-- Optional: space-separated list of scope names. -->
    <GenerateResponse enabled="true"/>
</OAuthV2>

Catat elemen <Scope>. Atribut ini digunakan untuk menentukan cakupan mana yang akan diterima oleh kebijakan.

Dalam contoh ini, kebijakan hanya akan berhasil jika token akses menyertakan cakupan "A". Jika elemen <Scope> ini dihilangkan atau jika tidak memiliki nilai, kebijakan akan mengabaikan cakupan token akses.

Kini, dengan kemampuan untuk memvalidasi token akses berdasarkan cakupan, Anda dapat mendesain API untuk menerapkan cakupan tertentu. Anda melakukannya dengan mendesain alur kustom beserta kebijakan VerifyAccessToken yang terikat cakupannya.

Misalnya, API Anda memiliki flow yang ditentukan untuk endpoint /resourceA:

<Flow name="resourceA">
            <Condition>(proxy.pathsuffix MatchesPath "/resourceA") and (request.verb = "GET")</Condition>
            <Description>Get a resource A</Description>
            <Request>
                <Step>
                    <Name>OAuthV2-VerifyAccessTokenA</Name>
                </Step>
            </Request>
            <Response>
                <Step>
                    <Name>AssignMessage-CreateResponse</Name>
                </Step>
            </Response>
        </Flow>

Saat alur ini dipicu (permintaan disertakan dengan /resourceA di akhiran jalur), kebijakan OAuthV2-VerifyAccessTokenA akan segera dipanggil. Kebijakan ini memverifikasi bahwa token akses valid dan akan melihat cakupan apa yang didukung token. Jika kebijakan dikonfigurasi seperti dalam contoh di bawah, dengan <Scope>A</Scope>, kebijakan hanya akan berhasil jika token akses memiliki cakupan "A". Jika tidak, {i>error<i} akan muncul.

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Singkatnya, developer API bertanggung jawab untuk mendesain penerapan cakupan ke dalam API mereka. Mereka melakukannya dengan membuat alur kustom untuk menangani cakupan tertentu, dan melampirkan kebijakan VerifyAccessToken untuk menerapkan cakupan tersebut.

Contoh kode

Terakhir, mari kita lihat beberapa contoh panggilan API untuk membantu menggambarkan cara token menerima cakupan dan penerapan cakupan.

Kapitalisasi default

Misalnya Anda memiliki aplikasi developer dengan berbagai produk, dan gabungan dari cakupan produk tersebut adalah: A, B, dan C. Panggilan API ini meminta token akses, tetapi tidak menetapkan parameter kueri cakupan.

curl -X POST -H content-type:application/x-www-form-urlencoded \
  https://apitest.acme.com/scopecheck1/token?grant_type=client_credentials

Dalam hal ini, token yang dihasilkan akan diberi cakupan A, B, dan C (perilaku default). Metadata token akan terlihat seperti ini:

{
  "issued_at" : "1417016208588",
  "application_name" : "eb1a0333-5775-4116-9eb2-c36075ddc360",
  "scope" : "A B C",
  "status" : "approved",
  "api_product_list" : "[scopecheck1-yEgQbQqjRR]",
  "expires_in" : "1799", //--in seconds
  "developer.email" : "scopecheck1-yxiuHuZcDW@apigee.com",
  "organization_id" : "0",
  "token_type" : "BearerToken",
  "client_id" : "atGFvl3jgA0pJd05rXKHeNAC69naDmpW",
  "access_token" : "MveXpj4UYXol38thNoJYIa8fBGlI",
  "organization_name" : "wwitman",
  "refresh_token_expires_in" : "0", //--in seconds
  "refresh_count" : "0"
}

Sekarang, misalkan Anda memiliki endpoint API dengan cakupan "A" (artinya, VerifyAccessToken memerlukan cakupan "A"). Berikut kebijakan VerifyAccessToken:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenA">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Berikut adalah contoh panggilan ke dan endpoint yang menerapkan cakupan A:

curl -X GET -H Authorization: Bearer MveXpj4UYXol38thNoJYIa8fBGlI \
  https://apitest.acme.com/scopecheck1/resourceA

Panggilan GET ini berhasil:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }

Pengujian ini berhasil karena kebijakan VerifyAccessToken yang dipicu saat endpoint dipanggil memerlukan cakupan A, dan token akses diberi cakupan A, B, dan C -- perilaku default.

Kasus pemfilteran

Misalkan Anda memiliki aplikasi developer dengan produk yang memiliki cakupan A, B, C, dan X. Anda meminta token akses dan menyertakan parameter kueri scope, seperti ini:

curl -i -X POST -H content-type:application/x-www-form-urlencoded \
  'https://apitest.acme.com/oauth/token?grant_type=client_credentials&scope=A X'

Dalam hal ini, token yang dihasilkan akan diberi cakupan A dan X, karena A dan X adalah cakupan yang valid. Ingat bahwa aplikasi developer mengenali cakupan A, B, C, dan X. Dalam hal ini, Anda memfilter daftar produk API berdasarkan cakupan tersebut. Jika produk memiliki cakupan A atau X, Anda dapat mengonfigurasi endpoint API yang akan menerapkan cakupan ini. Jika produk tidak memiliki cakupan A atau X (katakanlah produk tersebut memiliki B,C, dan Z), API yang menerapkan cakupan A atau X tidak dapat dipanggil dengan token tersebut.

Saat Anda memanggil API dengan token baru:

curl -X GET -H Authorization: Bearer Rkmqo2UkEIyIBCrtro1QpIG \
  https://apitest.acme.com/scopecheck1/resourceX

Token akses divalidasi oleh proxy API. Contoh:

<OAuthV2 async="false" continueOnError="false" enabled="true" name="OAuthV2-VerifyAccessTokenX">
    <DisplayName>Verify OAuth v2.0 Access Token</DisplayName>
    <ExternalAuthorization>false</ExternalAuthorization>
    <Operation>VerifyAccessToken</Operation>
    <Scope>A X</Scope>
    <GenerateResponse enabled="true"/>
</OAuthV2>

Pemicu panggilan GET berhasil dan mengembalikan respons. Contoh:

 {
   "hello" : "Tue, 25 Nov 2014 01:35:53 UTC"
 }
 

Eksperimen berhasil karena kebijakan VerifyAccessToken memerlukan cakupan A atau X, dan token akses mencakup cakupan A dan X. Tentu saja, jika elemen <Scope> ditetapkan ke "B", panggilan ini akan gagal.

Ringkasan

Penting untuk memahami cara Apigee menangani cakupan OAuth 2.0. Berikut adalah poin-poin penting:

  • Aplikasi developer "mengenali" gabungan semua cakupan yang ditentukan untuk semua produknya.
  • Saat meminta token akses, aplikasi memiliki kesempatan untuk menentukan cakupan mana yang ingin dimiliki. Apigee (server otorisasi) dapat menentukan cakupan mana yang benar-benar akan ditetapkan ke token akses berdasarkan (a) cakupan yang diminta dan (b) cakupan yang dikenali oleh aplikasi developer.
  • Jika Apigee tidak dikonfigurasi untuk memeriksa cakupan (elemen <Scope> tidak ada dalam kebijakan VerifyAccessToken atau kosong), panggilan API akan berhasil asalkan cakupan yang disematkan dalam token akses cocok dengan salah satu cakupan yang dikenali oleh aplikasi developer terdaftar (salah satu cakupan dalam daftar cakupan "master" aplikasi).
  • Jika token akses tidak memiliki cakupan yang terkait dengannya, token tersebut hanya akan berhasil jika Apigee tidak mempertimbangkan cakupan (elemen <Scope> tidak ada dalam kebijakan VerifyAccessToken atau kosong).