Jika Looker disematkan dalam iframe menggunakan penyematan bertanda tangan, beberapa browser secara default menggunakan kebijakan cookie yang memblokir cookie pihak ketiga. Cookie pihak ketiga ditolak saat iframe sematan dimuat dari domain yang berbeda dengan domain yang memuat aplikasi sematan. Anda biasanya dapat mengatasi batasan ini dengan meminta dan menggunakan domain khusus. Namun, domain vanity tidak dapat digunakan dalam beberapa skenario. Untuk skenario inilah sematan tanpa cookie Looker dapat digunakan.
Bagaimana cara kerja penyematan tanpa cookie?
Jika cookie pihak ketiga tidak diblokir, cookie sesi akan dibuat saat pengguna pertama kali login ke Looker. Cookie ini dikirim dengan setiap permintaan pengguna, dan server Looker menggunakannya untuk menetapkan identitas pengguna yang memulai permintaan. Jika cookie diblokir, cookie tidak dikirim dengan permintaan, sehingga server Looker tidak dapat mengidentifikasi pengguna yang terkait dengan permintaan tersebut.
Untuk mengatasi masalah ini, sematan tanpa cookie Looker mengaitkan token dengan setiap permintaan yang dapat digunakan untuk membuat ulang sesi pengguna di server Looker. Aplikasi penyematan bertanggung jawab untuk mendapatkan token ini dan menyediakannya untuk instance Looker yang berjalan di iframe sematan. Proses untuk mendapatkan dan memberikan token ini dijelaskan di bagian lain dalam dokumen ini.
Untuk menggunakan salah satu API, aplikasi penyematan harus dapat melakukan autentikasi ke Looker API dengan hak istimewa admin. Domain sematan juga harus tercantum dalam Daftar yang Diizinkan untuk Domain Sematan, atau, jika menggunakan Looker 23.8 atau yang lebih baru, domain sematan dapat disertakan saat sesi tanpa cookie diperoleh.
Membuat iframe sematan Looker
Diagram urutan berikut menggambarkan pembuatan iframe sematan. Beberapa iframe dapat dibuat secara bersamaan atau di masa mendatang. Jika diterapkan dengan benar, iframe akan otomatis bergabung ke sesi yang dibuat oleh iframe pertama. Looker Embed SDK menyederhanakan proses ini dengan otomatis bergabung ke sesi yang ada.
- Pengguna melakukan tindakan di aplikasi penyematan yang menghasilkan pembuatan iframe Looker.
- Klien aplikasi penyematan mendapatkan sesi Looker. Looker Embed SDK dapat digunakan untuk memulai sesi ini, tetapi URL endpoint atau fungsi callback harus disediakan. Jika fungsi callback digunakan, fungsi tersebut akan memanggil server aplikasi penyematan untuk mendapatkan sesi penyematan Looker. Jika tidak, Embed SDK akan memanggil URL endpoint yang diberikan.
- Server aplikasi penyematan menggunakan Looker API untuk mendapatkan sesi penyematan. Panggilan API ini mirip dengan proses penandatanganan sematan bertanda tangan Looker, karena menerima definisi pengguna sematan sebagai input. Jika sesi sematan Looker sudah ada untuk pengguna yang melakukan panggilan, token referensi sesi terkait harus disertakan dalam panggilan. Hal ini akan dijelaskan secara lebih mendetail di bagian Memperoleh sesi dalam dokumen ini.
- Pemrosesan endpoint sesi sematan perolehan mirip dengan endpoint
/login/embed/(signed url)
yang ditandatangani, karena mengharapkan definisi pengguna sematan Looker sebagai isi permintaan, bukan di URL. Proses endpoint sesi sematan perolehan memvalidasi, lalu membuat atau memperbarui, pengguna sematan. API ini juga dapat menerima token referensi sesi yang ada. Hal ini penting karena memungkinkan beberapa iframe sematan Looker berbagi sesi yang sama. Pengguna yang disematkan tidak akan diupdate jika token referensi sesi diberikan dan sesi belum berakhir. Hal ini mendukung kasus penggunaan saat satu iframe dibuat menggunakan URL sematan yang ditandatangani dan iframe lainnya dibuat tanpa URL sematan yang ditandatangani. Dalam hal ini, iframe tanpa URL sematan bertanda tangan akan mewarisi cookie dari sesi pertama. - Panggilan Looker API menampilkan empat token, masing-masing dengan time to live (TTL):
- Token otorisasi (TTL = 30 detik)
- Token navigasi (TTL = 10 menit)
- Token API (TTL = 10 menit)
- Token referensi sesi (TTL = masa aktif sesi yang tersisa)
- Server aplikasi penyematan harus melacak data yang ditampilkan oleh data Looker dan mengaitkannya dengan pengguna yang memanggil dan agen pengguna browser pengguna yang memanggil. Saran tentang cara melakukannya diberikan di bagian Buat token dalam dokumen ini. Panggilan ini akan menampilkan token otorisasi, token navigasi, dan token API, beserta semua TTL terkait. Token referensi sesi harus diamankan dan tidak diekspos di browser yang memanggil.
Setelah token dikembalikan ke browser, URL login sematan Looker harus dibuat. Looker Embed SDK akan membuat URL login sematan secara otomatis. Untuk menggunakan
windows.postMessage
API guna membuat URL login sematan, lihat bagian Menggunakan Lookerwindows.postMessage
API dalam dokumen ini untuk melihat contohnya.URL login tidak berisi detail pengguna sematan yang ditandatangani. Objek ini berisi URI target, termasuk token navigasi, dan token otorisasi sebagai parameter kueri. Token otorisasi harus digunakan dalam waktu 30 detik dan hanya dapat digunakan satu kali. Jika iframe tambahan diperlukan, sesi penyematan harus diperoleh lagi. Namun, jika token referensi sesi diberikan, token otorisasi akan dikaitkan dengan sesi yang sama.
Endpoint login sematan Looker menentukan apakah login ditujukan untuk sematan tanpa cookie, yang ditandai dengan adanya token otorisasi. Jika token otorisasi valid, token tersebut akan memeriksa hal berikut:
- Sesi terkait masih valid.
- Pengguna sematan terkait masih valid.
- Agen pengguna browser yang terkait dengan permintaan cocok dengan agen browser yang terkait dengan sesi.
Jika pemeriksaan dari langkah sebelumnya berhasil, permintaan akan dialihkan menggunakan URI target yang ada dalam URL. Proses ini sama dengan proses untuk login sematan bertanda tangan Looker.
Permintaan ini adalah pengalihan untuk meluncurkan dasbor Looker. Permintaan ini akan memiliki token navigasi sebagai parameter.
Sebelum endpoint dieksekusi, server Looker akan mencari token navigasi dalam permintaan. Jika server menemukan token, server akan memeriksa hal berikut:
- Sesi terkait masih valid.
- Agen pengguna browser yang terkait dengan permintaan cocok dengan agen browser yang terkait dengan sesi.
Jika valid, sesi akan dipulihkan untuk permintaan dan permintaan dasbor akan berjalan.
HTML untuk memuat dasbor dikembalikan ke iframe.
UI Looker yang berjalan di iframe menentukan bahwa HTML dasbor adalah respons sematan tanpa cookie. Pada saat itu, UI Looker mengirim pesan ke aplikasi penyematan untuk meminta token yang diambil pada langkah 6. Kemudian, UI menunggu hingga menerima token. Jika token tidak tiba, pesan akan ditampilkan.
Aplikasi penyematan mengirimkan token ke iframe sematan Looker.
Saat token diterima, UI Looker yang berjalan di iframe akan memulai proses untuk merender objek permintaan. Selama proses ini, UI akan membuat panggilan API ke server Looker. Token API yang diterima pada langkah 15 otomatis disisipkan sebagai header ke semua permintaan API.
Sebelum endpoint dijalankan, server Looker mencari token API dalam permintaan. Jika server menemukan token, server akan memeriksa hal berikut:
- Sesi terkait masih valid.
- Agen pengguna browser yang terkait dengan permintaan cocok dengan agen browser yang terkait dengan sesi.
Jika valid, sesi akan dipulihkan untuk permintaan, dan permintaan API akan berjalan.
Data dasbor ditampilkan.
Dasbor dirender.
Pengguna memiliki kontrol atas dasbor.
Membuat token baru
Diagram urutan berikut menggambarkan pembuatan token baru.
- UI Looker yang berjalan di iframe sematan memantau TTL token sematan.
- Saat masa berlaku token hampir berakhir, UI Looker akan mengirimkan pesan token refresh ke klien aplikasi sematan.
- Klien aplikasi penyematan kemudian meminta token baru dari endpoint yang diterapkan di server aplikasi penyematan. Looker Embed SDK akan meminta token baru secara otomatis, tetapi URL endpoint atau fungsi callback harus diberikan. Jika digunakan, fungsi callback akan memanggil server aplikasi penyematan untuk membuat token baru. Jika tidak, Embed SDK akan memanggil URL endpoint yang diberikan.
- Aplikasi penyematan menemukan
session_reference_token
yang terkait dengan sesi sematan. Contoh yang disediakan di repositori Git Looker Embed SDK menggunakan cookie sesi, tetapi cache sisi server terdistribusi, misalnya Redis, juga dapat digunakan. - Server aplikasi penyematan memanggil server Looker dengan permintaan untuk membuat token. Permintaan ini juga memerlukan token API dan navigasi terbaru selain agen pengguna browser yang memulai permintaan.
- Server Looker memvalidasi agen pengguna, token referensi sesi, token navigasi, dan token API. Jika permintaan valid, token baru akan dibuat.
- Token ditampilkan ke server aplikasi penyematan yang memanggil.
- Server aplikasi penyematan menghapus token referensi sesi dari respons dan menampilkan respons yang tersisa ke klien aplikasi penyematan.
- Klien aplikasi penyematan mengirimkan token yang baru dibuat ke UI Looker. Looker Embed SDK akan melakukannya secara otomatis. Menyematkan klien aplikasi yang menggunakan
windows.postMessage
API akan bertanggung jawab untuk mengirim token. Setelah UI Looker menerima token, token tersebut akan digunakan dalam panggilan API dan navigasi halaman berikutnya.
Menerapkan sematan tanpa cookie Looker
Penyematan tanpa cookie Looker dapat diterapkan menggunakan Looker Embed SDK atau windows.postMessage
API. Anda dapat menggunakan metode Looker Embed SDK, tetapi contoh yang menunjukkan cara menggunakan windows.postMessage
API juga tersedia. Penjelasan mendetail tentang kedua penerapan dapat ditemukan di file README SDK Sematan Looker. Repositori git Embed SDK juga berisi implementasi yang berfungsi.
Mengonfigurasi instance Looker
Penyematan tanpa cookie memiliki kesamaan dengan penyematan bertanda tangan Looker. Untuk menggunakan penyematan tanpa cookie, admin harus mengaktifkan Autentikasi SSO Sematan. Namun, tidak seperti penyematan bertanda tangan Looker, penyematan tanpa cookie tidak menggunakan setelan Embed Secret. Penyematan tanpa cookie menggunakan Token Web JSON (JWT) dalam bentuk setelan Rahasia JWT Sematan, yang dapat ditetapkan atau direset di halaman Sematkan di bagian Platform pada menu Admin.
Menetapkan secret JWT tidak diperlukan, karena upaya pertama untuk membuat sesi sematan tanpa cookie akan membuat JWT. Hindari mereset token ini, karena tindakan tersebut akan membatalkan semua sesi sematan tanpa cookie yang aktif.
Tidak seperti rahasia sematan, rahasia JWT sematan tidak pernah diekspos, karena hanya digunakan secara internal di server Looker.
Implementasi klien aplikasi
Bagian ini menyertakan contoh cara menerapkan penyematan tanpa cookie di klien aplikasi dan berisi subbagian berikut:
- Menginstal dan memperbarui Looker Embed SDK
- Menggunakan Looker Embed SDK
- Menggunakan Looker
windows.postMessage
API
Menginstal atau mengupdate Looker Embed SDK
Versi Looker SDK berikut diperlukan untuk menggunakan penyematan tanpa cookie:
@looker/embed-sdk >= 2.0.0
@looker/sdk >= 22.16.0
Menggunakan Looker Embed SDK
Metode inisialisasi baru telah ditambahkan ke Embed SDK untuk memulai sesi tanpa cookie. Metode ini menerima dua string URL atau dua fungsi callback. String URL harus mereferensikan endpoint di server aplikasi penyematan. Detail penerapan endpoint ini di server aplikasi dibahas di bagian Penerapan server aplikasi dalam dokumen ini.
getEmbedSDK().initCookieless(
runtimeConfig.lookerHost,
'/acquire-embed-session',
'/generate-embed-tokens'
)
Contoh berikut menunjukkan cara penggunaan callback. Callback hanya boleh digunakan jika aplikasi klien penyematan perlu mengetahui status sesi penyematan Looker. Anda juga dapat menggunakan peristiwa session:status
, sehingga tidak perlu menggunakan callback dengan Embed SDK.
const acquireEmbedSessionCallback =
async (): Promise<LookerEmbedCookielessSessionData> => {
const resp = await fetch('/acquire-embed-session')
if (!resp.ok) {
console.error('acquire-embed-session failed', { resp })
throw new Error(
`acquire-embed-session failed: ${resp.status} ${resp.statusText}`
)
}
return (await resp.json()) as LookerEmbedCookielessSessionData
}
const generateEmbedTokensCallback =
async ({ api_token, navigation_token }): Promise<LookerEmbedCookielessSessionData> => {
const resp = await fetch('/generate-embed-tokens', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ api_token, navigation_token }),
})
if (!resp.ok) {
console.error('generate-embed-tokens failed', { resp })
throw new Error(
`generate-embed-tokens failed: ${resp.status} ${resp.statusText}`
)
}
return (await resp.json()) as LookerEmbedCookielessSessionData
}
getEmbedSDK().initCookieless(
runtimeConfig.lookerHost,
acquireEmbedSessionCallback,
generateEmbedTokensCallback
)
Menggunakan Looker windows.postMessage
API
Anda dapat melihat contoh mendetail penggunaan windows.postMessage
API dalam file message_example.ts
dan message_utils.ts
di repositori Git Embed SDK. Sorotan contohnya dijelaskan di sini.
Contoh berikut menunjukkan cara membuat URL untuk iframe. Fungsi callback identik dengan contoh acquireEmbedSessionCallback
yang terlihat sebelumnya.
private async getCookielessLoginUrl(): Promise<string> {
const { authentication_token, navigation_token } =
await this.embedEnvironment.acquireSession()
const url = this.embedUrl.startsWith('/embed')
? this.embedUrl
: `/embed${this.embedUrl}`
const embedUrl = new URL(url, this.frameOrigin)
if (!embedUrl.searchParams.has('embed_domain')) {
embedUrl.searchParams.set('embed_domain', window.location.origin)
}
embedUrl.searchParams.set('embed_navigation_token', navigation_token)
const targetUri = encodeURIComponent(
`${embedUrl.pathname}${embedUrl.search}${embedUrl.hash}`
)
return `${embedUrl.origin}/login/embed/${targetUri}?embed_authentication_token=${authentication_token}`
}
Contoh berikut menunjukkan cara memproses permintaan token, membuat token baru, dan mengirimkannya ke Looker. Fungsi callback identik dengan contoh generateEmbedTokensCallback
sebelumnya.
this.on(
'session:tokens:request',
this.sessionTokensRequestHandler.bind(this)
)
private connected = false
private async sessionTokensRequestHandler(_data: any) {
const contentWindow = this.getContentWindow()
if (contentWindow) {
if (!this.connected) {
// When not connected the newly acquired tokens can be used.
const sessionTokens = this.embedEnvironment.applicationTokens
if (sessionTokens) {
this.connected = true
this.send('session:tokens', this.embedEnvironment.applicationTokens)
}
} else {
// If connected, the embedded Looker application has decided that
// it needs new tokens. Generate new tokens.
const sessionTokens = await this.embedEnvironment.generateTokens()
this.send('session:tokens', sessionTokens)
}
}
}
send(messageType: string, data: any = {}) {
const contentWindow = this.getContentWindow()
if (contentWindow) {
const message: any = {
type: messageType,
...data,
}
contentWindow.postMessage(JSON.stringify(message), this.frameOrigin)
}
return this
}
Implementasi server aplikasi
Bagian ini menyertakan contoh cara menerapkan penyematan tanpa cookie di server aplikasi dan berisi subbagian berikut:
Penerapan dasar
Aplikasi penyematan harus menerapkan dua endpoint sisi server yang akan memanggil endpoint Looker. Hal ini dilakukan untuk memastikan bahwa token referensi sesi tetap aman. Berikut adalah endpoint-nya:
- Mendapatkan sesi — Jika token referensi sesi sudah ada dan masih aktif, permintaan untuk sesi akan bergabung dengan sesi yang ada. Sesi perolehan dipanggil saat iframe dibuat.
- Membuat token — Looker memicu panggilan ke endpoint ini secara berkala.
Mendapatkan sesi
Contoh ini di TypeScript menggunakan sesi untuk menyimpan atau memulihkan token referensi sesi. Endpoint tidak harus diterapkan di TypeScript.
app.get(
'/acquire-embed-session',
async function (req: Request, res: Response) {
try {
const current_session_reference_token =
req.session && req.session.session_reference_token
const response = await acquireEmbedSession(
req.headers['user-agent']!,
user,
current_session_reference_token
)
const {
authentication_token,
authentication_token_ttl,
navigation_token,
navigation_token_ttl,
session_reference_token,
session_reference_token_ttl,
api_token,
api_token_ttl,
} = response
req.session!.session_reference_token = session_reference_token
res.json({
api_token,
api_token_ttl,
authentication_token,
authentication_token_ttl,
navigation_token,
navigation_token_ttl,
session_reference_token_ttl,
})
} catch (err: any) {
res.status(400).send({ message: err.message })
}
}
)
async function acquireEmbedSession(
userAgent: string,
user: LookerEmbedUser,
session_reference_token: string
) {
await acquireLookerSession()
try {
const request = {
...user,
session_reference_token: session_reference_token,
}
const sdk = new Looker40SDK(lookerSession)
const response = await sdk.ok(
sdk.acquire_embed_cookieless_session(request, {
headers: {
'User-Agent': userAgent,
},
})
)
return response
} catch (error) {
console.error('embed session acquire failed', { error })
throw error
}
}
Mulai Looker 23.8, domain sematan dapat disertakan saat sesi tanpa cookie diperoleh. Cara ini merupakan alternatif untuk menambahkan domain sematan menggunakan panel Admin > Sematan Looker. Looker menyimpan domain sematan di database internal Looker, sehingga tidak akan ditampilkan di panel Admin > Sematkan. Sebagai gantinya, domain sematan dikaitkan dengan sesi tanpa cookie dan hanya ada selama durasi sesi. Tinjau praktik terbaik keamanan jika Anda memutuskan untuk memanfaatkan fitur ini.
Membuat token
Contoh ini di TypeScript menggunakan sesi untuk menyimpan atau memulihkan token referensi sesi. Endpoint tidak harus diterapkan di TypeScript.
Penting bagi Anda untuk mengetahui cara menangani respons 400, yang terjadi saat token tidak valid. Meskipun respons 400 tidak seharusnya terjadi, jika terjadi, praktik terbaiknya adalah menghentikan sesi sematan Looker. Anda dapat mengakhiri sesi sematan Looker dengan menghancurkan iframe sematan atau dengan menyetel nilai session_reference_token_ttl
ke nol dalam pesan session:tokens
. Jika Anda menetapkan nilai session_reference_token_ttl
ke nol, iframe Looker akan menampilkan dialog sesi berakhir.
Respons 400 tidak ditampilkan saat sesi sematan berakhir. Jika sesi sematan telah berakhir, respons 200 akan ditampilkan dengan nilai session_reference_token_ttl
yang ditetapkan ke nol.
app.put(
'/generate-embed-tokens',
async function (req: Request, res: Response) {
try {
const session_reference_token = req.session!.session_reference_token
const { api_token, navigation_token } = req.body as any
const tokens = await generateEmbedTokens(
req.headers['user-agent']!,
session_reference_token,
api_token,
navigation_token
)
res.json(tokens)
} catch (err: any) {
res.status(400).send({ message: err.message })
}
}
)
}
async function generateEmbedTokens(
userAgent: string,
session_reference_token: string,
api_token: string,
navigation_token: string
) {
if (!session_reference_token) {
console.error('embed session generate tokens failed')
// missing session reference treat as expired session
return {
session_reference_token_ttl: 0,
}
}
await acquireLookerSession()
try {
const sdk = new Looker40SDK(lookerSession)
const response = await sdk.ok(
sdk.generate_tokens_for_cookieless_session(
{
api_token,
navigation_token,
session_reference_token: session_reference_token || '',
},
{
headers: {
'User-Agent': userAgent,
},
}
)
)
return {
api_token: response.api_token,
api_token_ttl: response.api_token_ttl,
navigation_token: response.navigation_token,
navigation_token_ttl: response.navigation_token_ttl,
session_reference_token_ttl: response.session_reference_token_ttl,
}
} catch (error: any) {
if (error.message?.includes('Invalid input tokens provided')) {
// The Looker UI does not know how to handle bad
// tokens. This shouldn't happen but if it does expire the
// session. If the token is bad there is not much that that
// the Looker UI can do.
return {
session_reference_token_ttl: 0,
}
}
console.error('embed session generate tokens failed', { error })
throw error
}
Pertimbangan penerapan
Aplikasi penyematan harus melacak token referensi sesi dan harus menjaganya tetap aman. Token ini harus dikaitkan dengan pengguna aplikasi yang disematkan. Token aplikasi penyematan dapat disimpan dengan salah satu cara berikut:
- Dalam sesi pengguna aplikasi yang disematkan
- Di cache sisi server yang tersedia di seluruh lingkungan bercluster
- Dalam tabel {i>database<i} yang terkait dengan pengguna
Jika sesi disimpan sebagai cookie, cookie tersebut harus dienkripsi. Contoh di repositori SDK sematan menggunakan cookie sesi untuk menyimpan token referensi sesi.
Saat sesi sematan Looker berakhir, dialog akan ditampilkan di iframe sematan. Pada tahap ini, pengguna tidak akan dapat melakukan apa pun di instance yang disematkan. Jika hal ini terjadi, peristiwa session:status
akan dibuat, sehingga aplikasi penyematan dapat mendeteksi status aplikasi Looker yang disematkan saat ini dan mengambil tindakan tertentu.
Aplikasi penyematan dapat mendeteksi apakah sesi sematan telah berakhir dengan memeriksa apakah nilai session_reference_token_ttl
yang ditampilkan oleh endpoint generate_tokens
adalah nol. Jika nilainya nol, sesi sematan telah berakhir. Pertimbangkan untuk menggunakan fungsi callback untuk membuat token saat sematan tanpa cookie sedang diinisialisasi. Fungsi callback kemudian dapat menentukan apakah sesi sematan telah berakhir dan akan menghancurkan iframe sematan sebagai alternatif untuk menggunakan dialog sesi sematan berakhir default.
Menjalankan contoh sematan tanpa cookie Looker
Repositori SDK sematan berisi server dan klien node express yang ditulis dalam TypeScript yang mengimplementasikan aplikasi sematan. Contoh yang ditampilkan sebelumnya diambil dari penerapan ini. Bagian berikut mengasumsikan bahwa instance Looker Anda telah dikonfigurasi untuk menggunakan sematan tanpa cookie seperti yang dijelaskan sebelumnya.
Anda dapat menjalankan server sebagai berikut:
- Buat clone repositori Embed SDK —
git clone git@github.com:looker-open-source/embed-sdk.git
- Ubah direktori —
cd embed-sdk
- Instal dependensi —
npm install
- Konfigurasi server, seperti yang ditunjukkan di bagian Mengonfigurasi server dalam dokumen ini.
- Jalankan server —
npm run server
Mengonfigurasi server
Buat file .env
di root repositori yang di-clone (ini disertakan dalam .gitignore
).
Formatnya adalah sebagai berikut:
LOOKER_WEB_URL=your-looker-instance-url.com
LOOKER_API_URL=https://your-looker-instance-url.com
LOOKER_DEMO_HOST=localhost
LOOKER_DEMO_PORT=8080
LOOKER_EMBED_SECRET=embed-secret-from-embed-admin-page
LOOKER_CLIENT_ID=client-id-from-user-admin-page
LOOKER_CLIENT_SECRET=client-secret-from-user-admin-page
LOOKER_DASHBOARD_ID=id-of-dashboard
LOOKER_LOOK_ID=id-of-look
LOOKER_EXPLORE_ID=id-of-explore
LOOKER_EXTENSION_ID=id-of-extension
LOOKER_VERIFY_SSL=true
LOOKER_REPORT_ID=id-of-report
LOOKER_QUERY_VISUALIZATION_ID=id-of-query-visualization