Files
SnapOtter/apps/docs/id/guide/scim.md
T
SnapOtterandGitHub d10d0f544f fix: release QA hardening across processing, media, security, and CI gates (#649)
A release-readiness QA pass over the whole product. The commits split into
defects a user would hit and gates that were reporting green while measuring
nothing.

## Fixes that change behaviour

Rate limiting was bypassable on every install: TRUST_PROXY defaulted to true, so
request.ip came from a client-set header and a forged X-Forwarded-For got past
the login limiter. The default is now a private-network trust list.

A transient Postgres outage stranded in-flight jobs, leaving finished output on
disk with no row pointing at it. A reconciler now resolves those rows and adopts
the bytes rather than dropping the work.

A Redis connection that moved to a new address wedged every read-blocked
consumer, so completions stopped signalling while health still answered 200.
Socket timeouts plus subscriber pings recover it.

Installing more than one AI bundle left the shared venv multi-versioned and
silently broke three tools. The installer now reconciles distributions to one
version each.

Converting an image to JXL at quality 1 through 4 returned a 500, because
libjxl 0.7 rejects the distance those values compute. The quality is floored at
what the encoder honours. A missing ffmpeg was also reported to the user as a
corrupt upload; it now says the engine is unavailable.

RAW uploads reached an unpatched LibRaw on arm64, so it is built from source at
0.22.2, and the release scan was split so it can fail on an unfixed critical
instead of hiding it behind ignore-unfixed.

## Gates that could not fail

Two mutation lanes ran zero mutants because Stryker crawled the gitignored docs
build; coverage discarded its whole report on any failing test; the lint gate
skipped root tests, scripts, and two workspaces; and several generated matrices
counted a host missing ffmpeg as a passing tool. Each now measures what it
claims.

Full evidence and the outstanding release items are tracked locally and are not
part of this branch.
2026-07-27 15:37:30 +08:00

13 KiB

description, i18n_source_hash, i18n_provenance, i18n_output_hash, i18n_hash_version
description i18n_source_hash i18n_provenance i18n_output_hash i18n_hash_version
Siapkan provisioning SCIM 2.0 untuk menyinkronkan pengguna dan grup dari penyedia identitas Anda ke SnapOtter. Mencakup Okta, Azure AD / Entra ID, dan integrasi kustom. 06ee702b386e human a8677d4dd025 2

Provisioning SCIM

SnapOtter mengimplementasikan SCIM 2.0 (System for Cross-domain Identity Management) untuk provisioning pengguna dan grup secara otomatis. Penyedia identitas Anda dapat membuat, memperbarui, menonaktifkan, dan mengaktifkan kembali akun pengguna serta menyinkronkan keanggotaan grup secara otomatis.

::: tip Fitur enterprise Provisioning SCIM memerlukan lisensi enterprise dengan fitur scim. Fitur ini tidak tersedia pada paket team. Tanpa fitur tersebut, semua endpoint SCIM (kecuali discovery) mengembalikan 403. :::

Prasyarat

  • Sebuah instance SnapOtter yang berjalan dan dapat dijangkau melalui URL publik
  • Kunci lisensi enterprise dengan fitur scim
  • Akun SnapOtter admin bawaan dengan set izin efektif penuh. Peran khusus yang didelegasikan atau kunci API admin yang tidak memiliki izin admin tidak dapat membuat atau mencabut token SCIM global.
  • Akses admin ke pengaturan provisioning penyedia identitas Anda

Mulai cepat

  1. Buat token bearer SCIM:
curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
  -H "Cookie: snapotter-session=YOUR_SESSION" \
  -H "Content-Type: application/json"

Respons berisi token tersebut. Simpan segera; token tidak dapat diambil kembali.

{
  "token": "so_scim_v2_a1b2c3d4e5f6...",
  "message": "Save this token - it cannot be retrieved again"
}
  1. Pada penyedia identitas Anda, konfigurasikan provisioning SCIM dengan:
    • Base URL: https://photos.example.com/api/v1/scim/v2
    • Authentication: Bearer token (tempel token dari langkah 1)

Autentikasi

Endpoint SCIM menggunakan Bearer token khusus, terpisah dari sesi pengguna dan API key.

Membuat token

POST /api/v1/enterprise/scim/token menghasilkan token SCIM baru. Karena token dapat menyediakan dan mengubah pengguna di seluruh instans, titik akhir ini memerlukan peran admin bawaan dengan kumpulan izin admin efektif yang lengkap. Memegang users:manage dalam peran khusus saja tidak cukup.

Token dikembalikan dalam bentuk teks biasa tepat satu kali. SnapOtter hanya menyimpan hash scrypt. Jika Anda kehilangan token, cabut token tersebut dan buat yang baru.

Hanya satu token SCIM yang aktif pada satu waktu. Membuat token baru akan menggantikan token sebelumnya.

::: warning Penerbitan ulang token setelah peningkatan Token SCIM lama yang tidak berversi ditolak. Setelah meningkatkan ke rilis yang menerbitkan token so_scim_v2_..., buat token baru dan perbarui penyedia identitas Anda sebelum melanjutkan penyediaan. :::

Mencabut token

DELETE /api/v1/enterprise/scim/token mencabut token SCIM saat ini. Ini memiliki persyaratan admin bawaan yang sama dengan pembuatan token.

Pembatasan laju

Endpoint SCIM dibatasi hingga 1000 permintaan per menit per token. Melebihi batas ini mengembalikan HTTP 429.

Resource yang didukung

Resource SCIM Konsep SnapOtter Create Read Update Delete
User Akun pengguna Ya Ya Ya Soft delete
Group Team Ya Ya Ya Ya

::: warning SCIM Group dipetakan ke team SnapOtter, bukan role. SCIM tidak dapat mengatur role seorang pengguna. Semua pengguna yang dibuat melalui SCIM diberi role user. Untuk mengubah role pengguna, gunakan UI admin SnapOtter. :::

Operasi pengguna

Buat pengguna

POST /api/v1/scim/v2/Users

Membuat akun pengguna baru dengan authProvider diatur ke scim dan role user. Pengguna ditugaskan ke team Default. Jika active bernilai false, role diatur ke disabled sebagai gantinya.

Atribut wajib: userName. Opsional: externalId, emails, active (default true).

Daftar dan filter pengguna

GET /api/v1/scim/v2/Users

Mengembalikan daftar pengguna dengan paginasi. Mendukung parameter kueri startIndex dan count (maksimum 200 hasil per halaman).

Filtering hanya mendukung eq (equals), pada atribut berikut:

  • userName eq "jane"
  • externalId eq "ext-12345"

Operator filter dan atribut lain mengembalikan HTTP 400.

Ambil pengguna

GET /api/v1/scim/v2/Users/:id

Mengembalikan satu pengguna berdasarkan ID pengguna SnapOtter mereka.

Ganti pengguna

PUT /api/v1/scim/v2/Users/:id

Mengganti atribut pengguna. Mendukung userName, externalId, emails, dan active. Perubahan username diperiksa untuk konflik (409 jika username baru sudah dipakai pengguna lain).

Patch pengguna

PATCH /api/v1/scim/v2/Users/:id

Pembaruan sebagian menggunakan SCIM PatchOp. Operasi yang didukung:

Operasi Path
replace active, userName, externalId, emails, emails[type eq "work"].value, name.formatted, displayName
add Sama seperti replace
remove externalId, emails

Path name.formatted dan displayName diterima demi kompatibilitas tetapi tidak memiliki efek persisten (SnapOtter tidak menyimpan display name terpisah).

Operasi replace tanpa nilai (di mana value adalah objek tanpa path) juga didukung, dengan kunci userName, externalId, emails, dan active.

Nonaktifkan pengguna (soft delete)

DELETE /api/v1/scim/v2/Users/:id

SnapOtter tidak menghapus pengguna secara permanen melalui SCIM. Sebaliknya, DELETE melakukan deaktivasi lunak:

  1. Role pengguna diubah dari nilai saat ini (mis. editor) menjadi disabled:editor, sambil menyimpan role aslinya.
  2. Kata sandi pengguna dihapus.
  3. Semua sesi aktif dicabut.
  4. Semua API key dicabut.

Pengguna tidak lagi dapat masuk atau menggunakan API key mana pun. Data mereka (file, riwayat) tetap dipertahankan.

Aktifkan kembali pengguna

Untuk mengaktifkan kembali pengguna yang sebelumnya dinonaktifkan, kirim permintaan PUT atau PATCH dengan active: true. SnapOtter memulihkan role asli dari sebelum deaktivasi (mis. disabled:editor menjadi editor lagi). Jika role asli tidak dapat ditentukan, akan kembali ke user.

::: details Contoh: nonaktifkan dan aktifkan kembali melalui PATCH

// Deactivate
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    { "op": "replace", "path": "active", "value": false }
  ]
}

// Reactivate
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    { "op": "replace", "path": "active", "value": true }
  ]
}

:::

Operasi grup

SCIM Group dipetakan ke team SnapOtter. Membuat grup akan membuat team. Keanggotaan grup mengontrol team mana yang menjadi milik seorang pengguna.

Buat grup

POST /api/v1/scim/v2/Groups

Wajib: displayName. Opsional: members (array dari { value: userId }).

Daftar dan filter grup

GET /api/v1/scim/v2/Groups

Filtering hanya mendukung displayName eq "...". Dengan paginasi startIndex dan count (maksimum 200 hasil per halaman).

Ambil grup

GET /api/v1/scim/v2/Groups/:id

Ganti grup

PUT /api/v1/scim/v2/Groups/:id

Mengganti nama grup dan seluruh daftar keanggotaan. Anggota yang ada namun tidak ada dalam daftar baru dipindahkan ke team Default.

Patch grup

PATCH /api/v1/scim/v2/Groups/:id

Mendukung operasi berikut:

Operasi Path Efek
add members Menambahkan pengguna ke team
remove members[value eq "userId"] Memindahkan pengguna ke team Default
replace displayName Mengubah nama team
replace members Mengganti semua anggota (anggota yang dihapus dipindahkan ke team Default)

Hapus grup

DELETE /api/v1/scim/v2/Groups/:id

Menghapus team. Semua anggota team yang dihapus dipindahkan ke team Default. Pengguna tidak dinonaktifkan atau dihapus.

Penyiapan IdP

Okta

  1. Di konsol admin Okta, buka aplikasi SnapOtter Anda (atau buat baru).
  2. Buka tab Provisioning dan klik Configure API Integration.
  3. Centang Enable API Integration dan masukkan:
    • Base URL: https://photos.example.com/api/v1/scim/v2
    • API Token: Token bearer SCIM yang dibuat di atas
  4. Klik Test API Credentials, lalu Save.
  5. Di bawah Provisioning > To App, aktifkan:
    • Create Users
    • Update User Attributes
    • Deactivate Users
  6. Di bawah Push Groups, konfigurasikan grup Okta mana yang akan disinkronkan sebagai team SnapOtter.

Azure AD / Entra ID

  1. Di portal Azure, buka aplikasi enterprise SnapOtter Anda.
  2. Buka Provisioning dan atur Provisioning Mode ke Automatic.
  3. Di bawah Admin Credentials, masukkan:
    • Tenant URL: https://photos.example.com/api/v1/scim/v2
    • Secret Token: Token bearer SCIM yang dibuat di atas
  4. Klik Test Connection, lalu Save.
  5. Di bawah Mappings, konfigurasikan pemetaan atribut pengguna dan grup. Nilai default biasanya sudah berfungsi, tetapi pastikan userName dipetakan ke userPrincipalName atau mail sesuai keinginan.
  6. Atur Provisioning Status ke On dan simpan.

Azure melakukan provisioning pengguna dan grup pada siklus sinkronisasi tetap (biasanya setiap 40 menit).

Endpoint discovery

Ketiga endpoint ini tersedia tanpa autentikasi dan menjelaskan kemampuan server SCIM:

Endpoint Deskripsi
GET /api/v1/scim/v2/ServiceProviderConfig Kemampuan server dan fitur yang didukung
GET /api/v1/scim/v2/Schemas Definisi skema User dan Group
GET /api/v1/scim/v2/ResourceTypes Tipe resource yang tersedia (User, Group)

ServiceProviderConfig mengiklankan kemampuan berikut:

Fitur Didukung
Patch Ya
Bulk Tidak
Filter Ya (maks 200 hasil, hanya operator eq)
Change password Tidak
Sort Tidak
ETag Tidak

Batasan

  • Filtering: Hanya operator eq yang didukung. Filter kompleks, operator and/or, co (contains), dan sw (starts with) tidak diimplementasikan.
  • Operasi bulk: Tidak didukung.
  • Sort dan ETag: Tidak didukung.
  • Role: SCIM tidak dapat menetapkan role SnapOtter. Semua pengguna yang di-provisioning mendapat role user.
  • MAX_USERS: Batas variabel lingkungan MAX_USERS tidak diberlakukan pada pembuatan pengguna via SCIM. Jika Anda perlu membatasi jumlah pengguna, kelola penugasan di IdP Anda.
  • Satu token: Hanya satu token SCIM yang dapat aktif pada satu waktu. Jika beberapa IdP membutuhkan akses SCIM, mereka harus berbagi token.
  • Grup adalah team: SCIM Group berhubungan dengan team, bukan role atau grup izin.

Pemecahan masalah

403 "SCIM provisioning requires an enterprise license with the scim feature"

Lisensi Anda tidak menyertakan fitur scim, atau tidak ada lisensi yang dikonfigurasi. SCIM memerlukan lisensi paket enterprise. Pastikan SNAPOTTER_LICENSE_KEY telah diatur dan lisensi menyertakan fitur scim.

401 "Bearer token required"

Permintaan SCIM tidak menyertakan header Authorization: Bearer <token>. Periksa konfigurasi provisioning IdP Anda.

401 "Invalid token"

Format token salah, menggunakan format tidak berversi yang sudah tidak digunakan lagi, atau tidak cocok dengan hash yang disimpan. Hasilkan token so_scim_v2_... saat ini dan perbarui token di pengaturan penyediaan IdP Anda.

401 "SCIM not configured"

Belum ada token SCIM yang dibuat. Gunakan endpoint POST /api/v1/enterprise/scim/token untuk membuatnya.

409 "User already exists" / "userName already taken"

Pengguna dengan username yang sama sudah ada. Ini dapat terjadi ketika IdP mencoba ulang pembuatan yang gagal. Periksa username duplikat di panel admin SnapOtter.

429 "SCIM rate limit exceeded"

IdP mengirim lebih dari 1000 permintaan per menit. Ini biasanya terjadi selama sinkronisasi awal yang besar. Sebagian besar IdP otomatis mencoba ulang setelah jendela pembatasan laju direset. Jika masalah berlanjut, periksa interval sinkronisasi provisioning IdP Anda.

Pengguna di-deprovisioning tetapi tidak dihapus dari UI

SCIM DELETE adalah deaktivasi lunak. Pengguna yang dinonaktifkan tetap muncul dalam daftar pengguna admin dengan status dinonaktifkan. Ini disengaja agar data mereka tetap terjaga. Role mereka ditampilkan sebagai disabled:<original-role>.