منح الصلاحيات
عندما يحاول إخوتي رسم دائرة لاستبعادي، سأرسم دائرة أكبر لأضمهم إليها. وحيث يتحدثون عن امتيازات جماعة ضئيلة، سأصرخ من أجل حقوق البشرية جمعاء. —Pauli Murray
تأمّل معلومات ISP في KULoket للحظة. فخلف KULoket توجد قاعدة بيانات واسعة. وفي بداية كل فصل دراسي يمكنك إجراء تعديلات في معلومات ISP: مثل إضافة مقررات أو حذفها، وتعديل المجموعات في مرحلة أخرى غير مرحلتك الأساسية... ومن الواضح أنه لا يمكنك عرض معلومات ISP لطالب آخر، لأنها معلومات شخصية. لكن هل تساءلت يومًا من داخل UCLL لديه حق الوصول إلى معلومات ISP الخاصة بك؟ ومن يستطيع تغييرها؟
- مرشدك الطلابي (STC)، وهذا بديهي لأنك تستطيع مناقشة معلومات ISP مع مرشدك، الذي يجب عليه أيضًا أن يوافق عليها بالمناسبة.
- أشخاص من مكتب السكرتارية الطلابية، مثلًا، عليهم أحيانًا تعديل المجموعة الأساسية، فيحصلون هم أيضًا على حق الوصول.
- أما المحاضرون العاديون (بدون دور STC) فلا يمكنهم عرض معلومات ISP الخاصة بالطلاب.
وبعبارة أخرى، حقوق عرض معلومات ISP وتغييرها ليست متساوية للجميع. وهذا هو الحال في قاعدة بيانات أيضًا. ففي قاعدة بيانات يمكنك تحديد من يستطيع عرض البيانات وتغييرها. وتُسمّى حقوق الوصول هذه الصلاحيات (privileges).
وفي هذا القسم، سنعطيك نظرة مبسّطة إلى نظام الحقوق في PostgreSQL.
الصلاحيات - الحقوق
بصفتي مرشدًا طلابيًا (STC)، لديّ وصول محدود إلى جميع معلومات ISP في KULoket. وإذا انتقلت إلى معلومات ISP لابني David (الذي درس في KULeuven، أي ليس في UCLL)، أحصل على رسالة خطأ (بالهولندية) تفيد بأنني أستطيع النظر فيه فقط، لا تغييره:

وبذلك لديّ فعلًا الحق في الاطلاع على معلومات ISP والرجوع إليها، لكن ليس إجراء تغييرات عليها.
هل يمكنك التفكير في سبب يجعل مرشدًا طلابيًا في UCLL قادرًا على الرجوع إلى معلومات ISP لطلاب KULeuven؟
الحل
أحد الأسباب أن المرشد الطلابي في UCLL ينبغي أن يكون قادرًا على إرشاد الطلاب الجدد الذين كانوا يدرسون بالفعل في KULeuven. ولتقييم ما إذا كان يمكن لهذا الطالب الحصول على إعفاءات، من المنطقي أن يستطيع المرشد الطلابي طلب نظرة عامة على كل طالب في اتحاد KULeuven. وينبغي أن يرى المرشد فقط النقاط التي حصل عليها الطالب، لا العلامات التي حدث ذلك بها. لذا لا أستطيع رؤية تلك العلامات!
نتحدث عن "الصلاحيات" داخل PostgreSQL. ويمكن منح الصلاحيات لمستخدمين آخرين في SQL بـ GRANT ... PRIVILEGE ... TO. وسنعطي أولًا بعض الأمثلة ثم نناقش جمل GRANT التي يمكن أن تكون مفيدة في مهمة قاعدة بيانات تحتاج فيها إلى التعاون مع أشخاص آخرين داخل المخطط نفسه في قاعدة البيانات.
GRANT
ودون الدخول في التفاصيل، بعض الأمثلة أولًا:
GRANT USAGE ON SCHEMA examoef TO student: جميع المستخدمين الذين لديهم الدور "student" يحصلون على إمكانية الوصول إلى المخطط "examoef".GRANT SELECT ON TABLE customer TO local_r0987654: يُسمح للمستخدم "local_r0987654" بتنفيذ جملSELECTعلى جدول "customer" في المخطط الحالي.GRANT ALL ON ALL TABLES IN SCHEMA project TO local_01234567, local_02345678, local_03456789: امنح هؤلاء الطلاب الثلاثة جميع الأذونات على جميع الجداول التي تملكها.
تُعرّف حقوق الوصول بجملة GRANT. وهي واحدة من الجمل الأكثر تعقيدًا في SQL. وسنقتصر على الأمور المفيدة في العمل الجماعي. ومن التوثيق الموسّع لـ GRANT نستخلص بعض الاحتمالات. لا تهلع إن أرهقك ما يلي قليلًا. وسنفصّله في الأقسام التالية.
والتعريف الرسمي يبدو هكذا:
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
[, ...] | ALL [ PRIVILEGES ] }
ON { [ TABLE ] table_name [, ...]
| ALL TABLES IN SCHEMA schema_name [, ...] }
TO role_specification [, ...] [ WITH GRANT OPTION ]
[ GRANTED BY role_specification ]
GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
ON SCHEMA schema_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
[ GRANTED BY role_specification ]
لا هلع! عالج أولًا بقية هذا الفصل ثم عد لحظة إلى التعريف أعلاه. سيبدو بعد ذلك أسهل قراءة بكثير.
تمرين عملي متعلق بالحقوق
في ما يلي سنعمل عمليًا في PostgreSQL. والأفضل أن تنجز هذه التمارين في أزواج. ومن الممكن أيضًا إنجازها وحدك (مثلًا لطلاب التعلّم عن بعد). فكل طالب لديه بعد كل شيء مستخدمان منفصلان: رقم r الخاص به على الاتصال العادي 50203، وlocal_r-number الخاص به على اتصال التجميع 60203. وقد أُعدّت التمارين على شكل لعب أدوار بين مستخدمين اثنين ("Alpha" و"Bravo").
أُنشئت اللقطات والشيفرة أدناه للمستخدم "local_u0012047" ("Alpha"، ويؤدي دوره هنا المحاضر Jan) والمستخدم "local_0145920" ("Bravo"، المحاضر Steven). وإذا أنجزت التمرين بنفسك فاستبدل بالطبع اسمي المستخدمين بأرقام r الخاصة بك.
نفّذ الخطوات في النص العملي التالي. وإذا ساء شيء فتابع القراءة. فنحن نتركك عن قصد ترتكب أخطاء هنا وهناك لتتعلم منها...
المالك
أي شخص ينشئ كائنًا (مخططًا أو جدولًا...) في قاعدة بيانات يصبح تلقائيًا مالك هذا الكائن. نفّذ الآن الخطوات التالية في قاعدة البيانات الخاصة بمجموعتك ("1TX31"...):
- ينشئ Alpha مخططًا جديدًا بالاسم "u0012047_privileges" في اتصال التجميع 60203.
- ويستخدم Bravo اتصال التجميع أيضًا.
- ولا يملك الصلاحيات للقيام بأي شيء في هذا المخطط حاليًا سوى المالك. ولإثبات ذلك، يحاول Bravo إنشاء جدول في هذا المخطط.
ينشئ Bravo (عبر جملة CREATE) جدولًا بسيطًا جدًا "customer" بعمودين فقط: رقم العميل (عدد صحيح، وهذا هو المفتاح الأساسي فهو إلزامي) والاسم (varchar(50)، وهو إلزامي أيضًا). ولا تنسَ وضع اسم المخطط قبل اسم الجدول وإلا ستنشئ جدولًا جديدًا في public! وبشكل طبيعي، يحصل Bravo على رسالة خطأ على غرار:
ERROR: permission denied for schema u0012047_privileges
LINE 1: create table u0012047_privileges.customer (
^
SQL state: 42501
Character: 14
منح الحقوق على مخططك
لا يستطيع Bravo إنشاء كائنات جديدة (مثل جدول) في مخطط Alpha. والآن يقع على عاتق مالك المخطط إسناد الأذونات المناسبة لمستخدم آخر. ضع الآن الخطوات التالية موضع التطبيق:
يمنح Alpha حقوقًا معينة على المخطط لـ Bravo. وقد يكون ذلك محدودًا جدًا للاستخدام (USAGE) فقط، كما نفعل للمخطط في الامتحان. ففي النهاية لا نريد أن يجري الطلاب تغييراتهم الخاصة على المخطط (جداول جديدة ونحو ذلك). غير أن Alpha يريد أن يستطيع زميله العمل في مخططه، فيكتب الأمر التالي في أداة استعلامات:
GRANT ALL PRIVILEGES ON SCHEMA u0012047_privileges TO local_0145920;
--The word PRIVILEGES is not required, so shorter is:
GRANT ALL ON SCHEMA u0012047_privileges TO local_0145920
وإذا سار كل شيء على ما يرام، يردّ الخادم بـ:
GRANT
Query returned successfully in 60 msec.
حصل Bravo الآن على جميع الحقوق على مخطط Alpha. لكن... جميع الحقوق؟ يحاول Bravo إسقاط المخطط:
DROP SCHEMA u0012047_privileges;
يردّ خادم قاعدة البيانات برسالة خطأ:
ERROR: must be owner of schema u0012047_privileges
SQL state: 42501
وبعبارة أخرى، تعني ALL PRIVILEGES في الواقع "كل شيء باستثناء DROP". فلا يمكنك أبدًا إسقاط مخطط شخص آخر، إلا إذا كنت مستخدمًا فائقًا (superuser) لخادم قاعدة البيانات.
يحاول Bravo الآن مرة أخرى إنشاء جدول "customer" الجديد في مخطط Alpha. وينبغي أن ينجح ذلك الآن. جرّب هذا!
منح الحقوق على جدول
استطاع Bravo إنشاء الجدول الصغير "customer" بنجاح. ونجرّب الآن الأمور التالية على هذا الجدول.
يضيف Bravo عميلًا برقم 789 واسم "Dieter Desmedt" إلى الجدول. وينبغي أن يعمل ذلك دون مشكلة، انظر الشكل:
يحاول Alpha إضافة صف إلى جدول "customer" ("Wim Claes" برقم عميل 5). غير أنه يحصل على رسالة الخطأ التالية:
ERROR: permission denied for table customer state: 42501
رسالة الخطأ هذه منطقية، لأن Alpha ليس مالك كائن الجدول "customer". وكون Alpha يملك المخطط أمر غير ذي صلة، لأن الأمر يتعلق فقط بالأذونات على الجدول نفسه.
ويمنح Bravo الآن صلاحية INSERT لـ Alpha:
GRANT INSERT ON TABLE u0012047_privileges.customer to local_u0012047;
ويمكنك تصوّر تلك الأذونات بشكل جميل في pgAdmin. انقر بزر الفأرة الأيمن على جدول "client" واختر properties... ويخبرني الشكل أدناه أن local_0145920 هو مالك هذا الجدول:

وتقدّم علامة التبويب security معلومات إضافية:

وهناك كلمتان صعبتان هنا: "grantor" هو من يمنح الحقوق، و"grantee" هو متلقي الحقوق. وتوضح هذه اللقطة أن المستخدم local_u0145920 منح حقوق INSERT للمستخدم local_u0012047. وبالمناسبة، يمكنك تغيير الأذونات بنفسك في هذه العلامة وحفظ ذلك. غير أنه، على الأقل في الامتحان، ينبغي أن تكون قادرًا على فعل ذلك باستخدام جمل SQL فقط في pgAdmin.
والآن يستطيع Alpha إضافة صف إلى الجدول:
INSERT INTO u0012047_privileges.customer VALUES(5,'Wim Claes');
غير أن Alpha يلاحظ أن هذا ليس العميل الصحيح، لذا يجب إزالته:
DELETE FROM u0012047_privileges.customer
WHERE customer_number = 5;
اشرح ما يحدث عند تنفيذ هذا الاستعلام.
ويمنح Bravo أيضًا صلاحية DELETE لـ Alpha. ثم يحاول Alpha حذف العميل رقم 5 مرة أخرى بالاستعلام أعلاه. والنتيجة المفاجئة أنه يفشل لأن Alpha ليس لديه أذونات كافية! فكيف يكون ذلك؟ فمالك الجدول (Bravo) منح للتو أذونات DELETE، أليس كذلك؟
الجواب عن هذه الأسئلة في توثيق postgres. ونقتبس بإيجاز: "في الممارسة العملية، تتطلب أي جملة DELETE غير بسيطة صلاحية SELECT أيضًا، لأنها يجب أن تشير إلى أعمدة الجدول لتحديد الصفوف التي ستحذف.". وبما أن استعلام DELETE أعلاه يجب أن يكون قادرًا على select الصف ذا رقم العميل 5، فيجب أن يملك Alpha صلاحيات SELECT أيضًا.
يا Bravo، امنح أيضًا صلاحيات SELECT على جدولك، حتى يستطيع Alpha إزالة الصف الخاطئ. عظيم!
نظرة عامة على الحقوق
يمكنك إيجاد القائمة الكاملة للصلاحيات في الصفحة المذكورة بالفعل. وأكثرها إثارة للاهتمام بالنسبة لنا هي (والنظام أوسع كثيرًا من هذه النظرة الموجزة):
ALL: جميع الحقوق (باستثناءDROP).SELECT: تحديد عمود (أو أعمدة) في جدول. وهو مطلوب أيضًا في الغالب دائمًا لصلاحياتUPDATEوDELETE.UPDATE: الحق في تحديث الأعمدة في جدول.DELETE: حذف صفوف في جدول.CREATE: الحق في إنشاء مخطط جديد في قاعدة بيانات، أو إنشاء جدول جديد في مخطط موجود.USAGE: الحق في الوصول إلى مخطط.
في العمل الجماعي، ستمنح عمليًا جميع الأذونات لجميع أعضاء المجموعة. فشخص واحد ينشئ المخطط ويمنح الجميع الحقوق:
GRANT ALL ON SCHEMA ... TO local_r1, local_r2, local_r3
ثم يمنح كل طالب ينشئ جدولًا جديدًا في هذا المخطط الآخرين جميع الحقوق على تلك الجداول. ويمكنك أيضًا منح صلاحيات على جميع الجداول في مخطط:
GRANT ALL ON ALL TABLES IN SCHEMA ... TO ...
وهذا ما يفعله المحاضرون لمخطط الامتحان:
GRANT USAGE ON SCHEMA examschema TO student;
GRANT SELECT ON ALL TABLES IN SCHEMA examschema TO student;
وبعبارة أخرى، في الامتحان تحصل على إمكانية الوصول إلى جميع جداول المخطط ولا يمكنك سوى تنفيذ استعلامات SELECT.
REVOKE
كل ما يمكنك منحه من صلاحيات يمكنك أيضًا إزالته بـ REVOKE. ما عليك سوى استبدال كلمة GRANT بـ REVOKE في الأمثلة أعلاه.