Files
SnapOtter/apps/docs/ar/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

17 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
إعداد توفير SCIM 2.0 لمزامنة المستخدمين والمجموعات من موفّر الهوية لديك إلى SnapOtter. يغطي Okta وAzure AD / Entra ID والتكاملات المخصّصة. 06ee702b386e human 4e8347dee40e 2

توفير SCIM

يطبّق SnapOtter معيار SCIM 2.0 (نظام إدارة الهوية عبر النطاقات) للتوفير الآلي للمستخدمين والمجموعات. يمكن لموفّر الهوية لديك إنشاء حسابات المستخدمين وتحديثها وتعطيلها وإعادة تنشيطها ومزامنة عضويات المجموعات تلقائياً.

::: tip ميزة للمؤسسات يتطلّب توفير SCIM ترخيص enterprise مع ميزة scim. وهو غير متاح في خطة الفريق. وبدون هذه الميزة، تُعيد جميع نقاط نهاية SCIM (باستثناء الاكتشاف) رمز الحالة 403. :::

المتطلبات المسبقة

  • مثيل SnapOtter قيد التشغيل يمكن الوصول إليه عبر عنوان URL عام
  • مفتاح ترخيص enterprise مع ميزة scim
  • حساب SnapOtter admin مدمج مع مجموعة الأذونات الفعالة الكاملة الخاصة به. لا يمكن لدور مخصص مفوض أو مفتاح API للمشرف الذي يفتقد أي إذن مسؤول إنشاء أو إبطال الرمز المميز SCIM.
  • وصول المسؤول إلى إعدادات التوفير لدى موفّر الهوية

بداية سريعة

  1. أنشئ رمز حامل SCIM:
curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
  -H "Cookie: snapotter-session=YOUR_SESSION" \
  -H "Content-Type: application/json"

تحتوي الاستجابة على الرمز. احفظه فوراً؛ لا يمكن استرجاعه مرة أخرى.

{
  "token": "so_scim_v2_a1b2c3d4e5f6...",
  "message": "Save this token - it cannot be retrieved again"
}
  1. في موفّر الهوية لديك، اضبط توفير SCIM باستخدام:
    • عنوان URL الأساسي: https://photos.example.com/api/v1/scim/v2
    • المصادقة: رمز حامل (الصق الرمز من الخطوة 1)

المصادقة

تستخدم نقاط نهاية SCIM رمز حامل مخصّصاً، منفصلاً عن جلسات المستخدمين ومفاتيح API.

إنشاء رمز

يقوم POST /api/v1/enterprise/scim/token بإنشاء رمز SCIM جديد. نظرًا لأن الرمز المميز يمكنه توفير المستخدمين وتغييرهم عبر المثيل، فإن نقطة النهاية هذه تتطلب دور admin المدمج مع مجموعة أذونات المسؤول الفعالة الكاملة. إن الاحتفاظ بـ users:manage في دور مخصص ليس كافيًا.

يُعاد الرمز بنصّ صريح مرة واحدة فقط. يخزّن SnapOtter تجزئة scrypt فقط. إذا فقدت الرمز، فأبطِله وأنشئ رمزاً جديداً.

لا يكون سوى رمز SCIM واحد نشطاً في كل مرة. يؤدّي إنشاء رمز جديد إلى استبدال الرمز السابق.

::: warning إعادة إصدار الرمز المميز بعد الترقية يتم رفض الرموز المميزة SCIM القديمة التي لم يتم إصدارها. بعد الترقية إلى إصدار يُصدر رموز so_scim_v2_...، قم بإنشاء رمز مميز جديد وقم بتحديث موفر الهوية الخاص بك قبل استئناف التزويد. :::

إبطال رمز

يقوم DELETE /api/v1/enterprise/scim/token بإلغاء الرمز المميز SCIM الحالي. لديه نفس متطلبات المسؤول المضمنة الكاملة مثل إنشاء الرمز المميز.

تحديد المعدّل

تُقيّد نقاط نهاية SCIM بمعدّل 1000 طلب في الدقيقة لكل رمز. يؤدّي تجاوز هذا الحدّ إلى إعادة رمز الحالة HTTP 429.

الموارد المدعومة

مورد SCIM مفهوم SnapOtter إنشاء قراءة تحديث حذف
المستخدم حساب المستخدم نعم نعم نعم حذف مبدئي
المجموعة الفريق نعم نعم نعم نعم

::: warning تُطابَق مجموعات SCIM مع فرق SnapOtter، لا مع الأدوار. لا يستطيع SCIM ضبط دور المستخدم. يُخصَّص جميع المستخدمين المنشأين عبر SCIM للدور user. لتغيير دور المستخدم، استخدم واجهة مسؤول SnapOtter. :::

عمليات المستخدم

إنشاء مستخدم

POST /api/v1/scim/v2/Users

يُنشئ حساب مستخدم جديداً مع ضبط authProvider على scim والدور user. يُخصَّص المستخدم للفريق الافتراضي. إذا كان active يساوي false، فيُضبَط الدور على disabled بدلاً من ذلك.

السمات المطلوبة: userName. الاختيارية: externalId وemails وactive (القيمة الافتراضية true).

سرد المستخدمين وتصفيتهم

GET /api/v1/scim/v2/Users

يُعيد قائمة مصفّحة بالمستخدمين. يدعم معاملَي الاستعلام startIndex وcount (بحدّ أقصى 200 نتيجة لكل صفحة).

تدعم التصفية eq (يساوي) فقط، على هذه السمات:

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

تُعيد عوامل التصفية والسمات الأخرى رمز الحالة HTTP 400.

جلب مستخدم

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

يُعيد مستخدماً واحداً بحسب معرّف مستخدم SnapOtter الخاص به.

استبدال مستخدم

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

يستبدل سمات المستخدم. يدعم userName وexternalId وemails وactive. تُفحَص تغييرات اسم المستخدم بحثاً عن التعارضات (409 إذا كان اسم المستخدم الجديد مأخوذاً من قِبل مستخدم آخر).

تصحيح مستخدم

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

تحديث جزئي باستخدام SCIM PatchOp. العمليات المدعومة:

العملية المسارات
replace active وuserName وexternalId وemails وemails[type eq "work"].value وname.formatted وdisplayName
add نفس replace
remove externalId وemails

يُقبَل المساران name.formatted وdisplayName لأغراض التوافق لكن ليس لهما أثر دائم (لا يخزّن SnapOtter اسم عرض منفصلاً).

تُدعَم أيضاً عمليات replace عديمة القيمة (حيث تكون القيمة كائناً بلا path)، بالمفاتيح userName وexternalId وemails وactive.

تعطيل مستخدم (حذف مبدئي)

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

لا يحذف SnapOtter المستخدمين حذفاً نهائياً عبر SCIM. بدلاً من ذلك، تنفّذ عملية DELETE تعطيلاً مبدئياً:

  1. يُغيَّر دور المستخدم من قيمته الحالية (مثل editor) إلى disabled:editor، مع الحفاظ على الدور الأصلي.
  2. تُمحى كلمة مرور المستخدم.
  3. تُلغى جميع الجلسات النشطة.
  4. تُلغى جميع مفاتيح API.

لم يعُد بإمكان المستخدم تسجيل الدخول أو استخدام أي مفاتيح API. تُحفَظ بياناته (الملفات والسجل).

إعادة تنشيط مستخدم

لإعادة تنشيط مستخدم مُعطَّل سابقاً، أرسِل طلب PUT أو PATCH مع active: true. يستعيد SnapOtter الدور الأصلي من قبل التعطيل (مثلاً يعود disabled:editor إلى editor مرة أخرى). إذا تعذّر تحديد الدور الأصلي، فيُستخدَم user كبديل.

::: details مثال: التعطيل وإعادة التنشيط عبر 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 }
  ]
}

:::

عمليات المجموعة

تُطابَق مجموعات SCIM مع فرق SnapOtter. يؤدّي إنشاء مجموعة إلى إنشاء فريق. تتحكّم عضوية المجموعة في الفريق الذي ينتمي إليه المستخدم.

إنشاء مجموعة

POST /api/v1/scim/v2/Groups

مطلوب: displayName. اختياري: members (مصفوفة من { value: userId }).

سرد المجموعات وتصفيتها

GET /api/v1/scim/v2/Groups

تدعم التصفية displayName eq "..." فقط. مصفّحة بـstartIndex وcount (بحدّ أقصى 200 نتيجة لكل صفحة).

جلب مجموعة

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

استبدال مجموعة

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

يستبدل اسم المجموعة وقائمة العضوية الكاملة. يُنقَل الأعضاء الحاليون غير الموجودين في القائمة الجديدة إلى الفريق الافتراضي.

تصحيح مجموعة

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

يدعم هذه العمليات:

العملية المسار الأثر
add members يضيف المستخدمين إلى الفريق
remove members[value eq "userId"] ينقل المستخدم إلى الفريق الافتراضي
replace displayName يعيد تسمية الفريق
replace members يستبدل جميع الأعضاء (يُنقَل الأعضاء المزالون إلى الفريق الافتراضي)

حذف مجموعة

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

يحذف الفريق. يُنقَل جميع أعضاء الفريق المحذوف إلى الفريق الافتراضي. لا يُعطَّل المستخدمون ولا يُحذفون.

إعداد موفّر الهوية

Okta

  1. في وحدة تحكّم مسؤول Okta، افتح تطبيق SnapOtter لديك (أو أنشئ واحداً).
  2. انتقل إلى علامة التبويب Provisioning وانقر على Configure API Integration.
  3. حدّد Enable API Integration وأدخِل:
    • عنوان URL الأساسي: https://photos.example.com/api/v1/scim/v2
    • رمز API: رمز حامل SCIM المُنشأ أعلاه
  4. انقر على Test API Credentials ثم Save.
  5. تحت Provisioning > To App، فعّل:
    • Create Users
    • Update User Attributes
    • Deactivate Users
  6. تحت Push Groups، اضبط أي مجموعات Okta ستُزامَن كفرق SnapOtter.

Azure AD / Entra ID

  1. في بوابة Azure، انتقل إلى تطبيق SnapOtter للمؤسسات لديك.
  2. انتقل إلى Provisioning واضبط Provisioning Mode على Automatic.
  3. تحت Admin Credentials، أدخِل:
    • Tenant URL: https://photos.example.com/api/v1/scim/v2
    • Secret Token: رمز حامل SCIM المُنشأ أعلاه
  4. انقر على Test Connection ثم Save.
  5. تحت Mappings، اضبط تعيينات سمات المستخدم والمجموعة. عادةً ما تعمل الإعدادات الافتراضية، لكن تأكّد من أن userName يُطابَق مع userPrincipalName أو mail حسب رغبتك.
  6. اضبط Provisioning Status على On واحفظ.

يوفّر Azure المستخدمين والمجموعات على دورة مزامنة ثابتة (عادةً كل 40 دقيقة).

نقاط نهاية الاكتشاف

تتوفّر نقاط النهاية الثلاث هذه دون مصادقة وتصف قدرات خادم SCIM:

نقطة النهاية الوصف
GET /api/v1/scim/v2/ServiceProviderConfig قدرات الخادم والميزات المدعومة
GET /api/v1/scim/v2/Schemas تعريفات مخطّط المستخدم والمجموعة
GET /api/v1/scim/v2/ResourceTypes أنواع الموارد المتاحة (User وGroup)

يُعلن ServiceProviderConfig عن هذه القدرات:

الميزة مدعومة
Patch نعم
Bulk لا
Filter نعم (بحدّ أقصى 200 نتيجة، والعامل eq فقط)
تغيير كلمة المرور لا
Sort لا
ETag لا

القيود

  • التصفية: يُدعَم العامل eq فقط. أما عوامل التصفية المركّبة وعاملا and/or وco (يحتوي) وsw (يبدأ بـ) فهي غير مطبَّقة.
  • العمليات المجمّعة: غير مدعومة.
  • Sort وETag: غير مدعومين.
  • الأدوار: لا يستطيع SCIM تعيين أدوار SnapOtter. يحصل جميع المستخدمين المُوفَّرين على الدور user.
  • MAX_USERS: لا يُفرَض حدّ متغيّر البيئة MAX_USERS على إنشاء مستخدم SCIM. إذا احتجت إلى تحديد سقف لأعداد المستخدمين، فأدِر التعيينات في موفّر الهوية لديك.
  • رمز واحد: لا يمكن أن يكون سوى رمز SCIM واحد نشطاً في كل مرة. إذا احتاج عدة موفّري هوية إلى وصول SCIM، فعليهم مشاركة الرمز.
  • المجموعات هي فرق: تقابل مجموعات SCIM الفرق، لا الأدوار أو مجموعات الأذونات.

استكشاف الأخطاء وإصلاحها

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

ترخيصك لا يتضمّن ميزة scim، أو لا يوجد ترخيص مضبوط. يتطلّب SCIM ترخيص خطة enterprise. تأكّد من ضبط SNAPOTTER_LICENSE_KEY ومن أن الترخيص يتضمّن ميزة scim.

401 "Bearer token required"

لم يتضمّن طلب SCIM ترويسة Authorization: Bearer <token>. تحقّق من إعداد التوفير لدى موفّر الهوية.

401 "Invalid token"

الرمز مميز بشكل غير صحيح، أو يستخدم التنسيق الذي لم يتم إصداره، أو لا يتطابق مع التجزئة المخزنة. أنشئ رمز so_scim_v2_... الحالي وقم بتحديث الرمز المميز في إعدادات توفير IdP.

401 "SCIM not configured"

لم يُنشأ أي رمز SCIM بعد. استخدم نقطة النهاية POST /api/v1/enterprise/scim/token لإنشاء واحد.

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

يوجد مستخدم بنفس اسم المستخدم بالفعل. يمكن أن يحدث هذا عندما يعيد موفّر الهوية محاولة إنشاء فاشل. تحقّق من أسماء المستخدمين المكرّرة في لوحة مسؤول SnapOtter.

429 "SCIM rate limit exceeded"

يرسل موفّر الهوية أكثر من 1000 طلب في الدقيقة. يحدث هذا عادةً أثناء المزامنة الأولية الكبيرة. تعيد معظم موفّري الهوية المحاولة تلقائياً بعد إعادة ضبط نافذة تحديد المعدّل. إذا استمرّت المشكلة، فتحقّق من فاصل مزامنة التوفير لدى موفّر الهوية.

أُلغي توفير المستخدمين لكن لم يُزالوا من الواجهة

عملية SCIM DELETE هي تعطيل مبدئي. يظلّ المستخدمون المُعطَّلون يظهرون في قائمة مستخدمي المسؤول بحالة معطّلة. هذا مقصود بالتصميم للحفاظ على بياناتهم. يظهر دورهم بوصفه disabled:<original-role>.