Oauthlib: لم يعد تطبيق الويب الخاص بالعميل يرسل client_id

تم إنشاؤها على ٨ سبتمبر ٢٠١٨  ·  26تعليقات  ·  مصدر: oauthlib/oauthlib

لقد وجدت انحدارًا في المستوى الرئيسي عند استخدامه مع طلبات / طلبات oauthlib منذ أن تم دمج https://github.com/oauthlib/oauthlib/issues/495 . يتعلق الأمر بمنح التفويض / تطبيق الويب فقط.

الاستخدام الأساسي لطلبات oauthlib هو:

sess = OAuth2Session(client_id)
token = sess.fetch_token(token_url, client_secret=client_secret, authorization_response=request.url)

ومع ذلك ، منذ التغييرات ، تم تجاهل client_id للجلسة. أعتقد أن https://github.com/oauthlib/oauthlib/pull/505 أصلح حالة استخدام ولكنه كسر حالة أخرى. يجب أن نجد حلاً يربح فيه الجميع.

طلبات - استدعاء كود oauthlib على https://github.com/requests/requests-oauthlib/blob/master/requests_oauthlib/oauth2_session.py#L196 -L198 ومشكلة oauthlib هنا
https://github.com/oauthlib/oauthlib/blame/master/oauthlib/oauth2/rfc6749/clients/web_application.py#L128.

Bug Discussion OAuth2-Client

التعليق الأكثر فائدة

لن ترى كيف تريد تجاوز client_id بقيمة مختلفة ، لذا ستصوت لرفع استثناء إذا كانا مختلفين.

هل يجب علينا ، بالإضافة إلى ذلك ، تسجيل DeprecationWarning إذا تم تقديم client_id على الإطلاق كـ kwarg؟

ال 26 كومينتر

أول تفكيري هو إعادة التغييرات في prepare_request_body ، افتراضيًا ، استخدم self.client_id المعين في المُنشئ WebApplicationClient .
بعد ذلك ، يجب تغيير المستندات المضمنة في كفاية لإضافة &client_id=xx إلى الناتج prepare_request_body .

أخيرًا ، لاستبدال الإصلاح الأصلي ، سأقترح إزالة client_id من args ، وإضافة وسيطة جديدة إلى prepare_request_body مثل include_client=True/False لكليهما إضافة client_id و client_secret في الجسم ، أو عدم تضمينهما معًا.

أفكار؟

تضمين التغريدة Diaoulskionthedrow

ماذا عن:

سأقترح إزالة client_id من args ، وإضافة وسيطة جديدة لـ Prepar_request_body مثل include_client = True / False لإضافة كلٍ من client_id و client_secret في الجسم ، أو عدم تضمينهما معًا.

شكرا

لقد أطلقت بالفعل هذه المشكلة نفسها في أحد اختباراتي ، لكنني رفعتها ضد الطلبات / oauthlib هنا: https://github.com/requests/requests-oauthlib/issues/330

أعتقد أن المشكلة هي في الواقع خطأ request_oauthlib. مستنداتهم - في الواقع المثال الأول في مستنداتهم بالكامل عند تحميل الصفحة - يدعم تحديد client_id في مُنشئ OAuth2Session . يقوم المنطق في السطر 200 بسحب client_id من kwargs ، لكن ليس لديه احتياطي لسحبه من مثيل WebApplicationClient الذي تم إنشاؤه بالفعل.

jvanasco ، يمكن إصلاح المشكلة الحالية رقم 585 في طلبات oauthlib وحدها ، أو عن طريق إرجاع رقم PR # 505 الخاص بـ oauthlib. ومع ذلك ، لن يصلح أي من الحلول السلوك الذي ذكره skion في تعليقه على https://github.com/oauthlib/oauthlib/pull/505#issuecomment -351221107

وفقًا للمواصفات ، يجب إرسال المعلمة client_id للعملاء غير المصادق عليهم ، ولكن يفضل عدم إرسالها في نص طلب الرمز المميز للعملاء السريين ، كما هو الحال في هذه الحالة ، تكون الآلية المفضلة لمصادقة العميل عبر مصادقة HTTP الأساسية. ومع ذلك ، فإن فئة WebApplication تتضمنها دائمًا (مما يكسر بعض الخوادم) بالإضافة إلى أنها لا تقدم أي آلية لإزالتها.

يجب أن يوفر أوثليب طريقة أنيقة وبسيطة لطلبات أوثليب لحل المشكلة. إذا تمكنا من إيجاد حل في هذه المناقشة فسيكون ذلك رائعًا ؛ لأن هذا مانع ضخم.

هل يسمح بالسماح لـ client_id=False في prepare_request_body() بالمساعدة ، للإشارة إلى عدم إرسال معرف العميل؟ على الرغم من أنه حتى لو كان الأمر كذلك ، فقد يؤدي ذلك إلى هذا القبح بالقرب من السطر 126 :

client_id = None if client_id=False else self.client_id

آه لقد فهمت.

هل يوجد اختبار حالي للوحدة لمعرفة متى يجب إرسال client_id مقابل عدم إرساله؟ إذا لم يكن كذلك ، فهل لدى أي شخص قائمة يمكن استخدامها لإنشاء واحدة؟ سأكون سعيدًا لأخذ طعنة في إصلاح هذا وطلب oauthlib ، لأنه يمنع بعض أعمالي في الوقت الحالي.

تضمين التغريدة

سأقترح إزالة client_id من args ، وإضافة وسيطة جديدة لـ Prepar_request_body مثل include_client = True / False لإضافة كلٍ من client_id و client_secret في الجسم ، أو عدم تضمينهما معًا.

بقراءة هذا مرة أخرى ، أنا في الواقع أحب اقتراحك تمامًا. ربما يمكننا الابتعاد عن القيام بذلك بطريقة غير منقطعة ، لأن الوظيفة تأخذ بالفعل **kwargs .

ملاحظة واحدة:

لإضافة كل من client_id و client_secret في الجسم

نظرًا لأن هذا يتعلق بالعملاء العامين IIUC ، لا أعتقد أن client_secret متضمن ؛ إنها مجرد client_id تُضاف إلى الجسم؟ في هذه الحالة ، سأفكر أيضًا في إعادة تسمية المعلمة الجديدة إلى include_client_id=True/False .

في هذه الحالة ، سأفكر أيضًا في إعادة تسمية المعلمة الجديدة إلى include_client_id = True / False.

في الواقع ! client_secret غير مشارك لأنه غير موجود في WebApplicationClient .

jvanasco ، إذا كنت تريد إجراء
1) ارجع إلى https://github.com/oauthlib/oauthlib/pull/505
2) تغيير توقيع prepare_request_body() لإزالة client_id وإضافة include_client_id=True/False ( True (افتراضي): يضيف self.client_id )

بعد ذلك ، سيكون لدى طلبات oauthlib الخيار في https://github.com/requests/requests-oauthlib/blob/master/requests_oauthlib/oauth2_session.py#L196-L211 إما:
أ) قم بتضمين client_id وحده في الجسم

self._client.prepare_request_body(..)

ب) قم بتضمين client_id و client_secret في auth ولا تقم بتضمينهما في النص (الحل المفضل لـ RFC)

self._client.prepare_request_body(include_client_id=False, ..)
auth = requests.auth.HTTPBasicAuth(client_id, client_secret)

ج) تضمين client_id و client_secret في الجسم (حل بديل RFC)

self._client.prepare_request_body(client_secret=client_secret, ..)

سأقوم بتوليد العلاقات العامة لكلا المشروعين اليوم.

لدي الكثير من العلاقات العامة والاختبارات التي أجريت لـ OAuthlib. برغم من ذلك عندي سؤال...

هل يجب السماح باستخدام client_id كأداة kwarg؟ هذا جزئيًا للتوافق مع الإصدارات السابقة ، ولكن أيضًا لحالات الحافة. نظرًا لأن هذه الطريقة كانت معطلة إلى حد ما ، أعتقد أنه قد يكون من المفيد إما جعلها تعمل على النحو المنشود (مثل السماح لها في prepare_request_body لتجاوز self.client_id) أو رفع استثناء على الاستخدام غير الصحيح (كما في زيادة خطأ إذا تم توفير client_id ولكنه لا يتطابق مع self.client_id ).

لن ترى كيف تريد تجاوز client_id بقيمة مختلفة ، لذا ستصوت لرفع استثناء إذا كانا مختلفين.

هل يجب علينا ، بالإضافة إلى ذلك ، تسجيل DeprecationWarning إذا تم تقديم client_id على الإطلاق كـ kwarg؟

تم تقديم PR # 593. يؤدي إلى تحذير الإيقاف عند إرسال client_id ، وخطأ في القيمة إذا كان يختلف عن self.client_id . هناك أيضًا اختبار جديد يضمن الامتثال للسيناريوهات الثلاثة المفصلة JonathanHuot .

واجهت مشكلتي الأولى مع مرشح طلبات العلاقات العامة oauthlib وأنا أكتب بعض الاختبارات

يستدعي دائمًا prepare_request_body مع username=username, password=password . يبدو هذا خطأ. آمل أن يكون شخص ما هنا أكثر دراية بـ RFC ويعرف الإجابات على ما يلي:

  1. هل يجب أن يكون username + password أحد المعايير في request.body؟
  2. إذا ظهرت username + password في رأس مصادقة HTTP الأساسية ، فهل يجب تكرارها في نص الطلب؟
  3. هل من الممكن أن يكون لديك كل من معلمات الجسم username + password ورأس HTTPBasicAuth مع تفاصيل العميل؟

شكرا للوقوف في هذا.

  1. username و password يجب أن تكون دائما موجودة في نص طلب ل. يجب استخدامها فقط لمنح كلمة المرور ويعرف أيضًا باسم الإرث. يجب عدم استخدام هذه المنح الأخرى (ضمني ، رمز ، بيانات اعتماد العميل).
  2. مصادقة HTTP الأساسية اختيارية لبيانات اعتماد العميل (موصى بها للعملاء السريين على سبيل المثال مع client_secret ). يجب ألا تكون بيانات اعتماد المستخدم في HTTP Basic Auth.
  3. نعم

شكرا. فقط لتوضيح شيئين ، ولا تتردد في التحدث معي كأنني في الخامسة من عمري. أريد التأكد من أنني حصلت على هذا والاختبارات بشكل صحيح:

  1. يتم استخدام اسم المستخدم وكلمة المرور فقط في نوع معين من المنح التي تتطلبها. إذا تم استخدامها ، فقد تكون موجودة فقط في نص الطلب.

ما لم يتم تحديدها بشكل صريح يجب ألا تكون موجودة ، أليس كذلك؟

  1. إذا كانت المصادقة الأساسية لـ Http مخصصة فقط لبيانات اعتماد العميل ، فيجب ألا تحتوي الطلبات الحالية - oauthlib على الكتلة التي تنشئ مصادقة أساسية من مجموعة اسم المستخدم وكلمة المرور.

من فضلك اغفر لي كوني مطولة ومهووسة بهذه التفاصيل الصغيرة. أريد فقط التأكد من أن j يحصل على السلوك الصحيح ويمكنه كتابة اختبارات تضمن عدم تعرضنا لانحدار آخر.

jvanasco ، يمكنني requests-oauthlib و flask-oauthlib معًا.

  1. نعم

صيح.

  1. نعم ، AFAIU لا ينبغي أن تحتوي على هذه الكتلة https://github.com/requests/requests-oauthlib/blob/master/requests_oauthlib/oauth2_session.py#L207 -L211.

أفهم ، ولكن سيكون من الجيد المقارنة مع واقع المجال ؛ أي طلبات oauthlib ومختلف خبرات مقدمي الخدمة العامة. طلبات متعددة - مناقشات oauthlib https://github.com/requests/requests-oauthlib/issues/218 ، https://github.com/requests/requests-oauthlib/issues/211 ، https://github.com/requests / طلبات oauthlib / قضايا / 264 ، حدث بالفعل.

أعتقد أن لديهم ارتباكًا بين client password و client secret وهما في الواقع كلمتان لنفس الشيء بالضبط.
إذا اتبعنا الأساس المنطقي وراء https://github.com/requests/requests-oauthlib/pull/206 ، فلا يجب أن يكون محتوى العلاقات العامة مثل إضافة HTTPAuth(username, password) ولكن يجب أن يكون HTTPAuth(client_id, client_secret (كلمة مرور العميل).

PokeLukasa و chaosct و ibuchanan الذين شاركوا في مناقشات طلبات oauthlib.

رائعة! شكرا جزيلا. اعتقدت أن هذا هو ما يحدث ولكني أردت التأكيد.

أعتقد أنني أعرف كيف أرغب في تنظيم طلبات الطلبات الآن. لدي عدد قليل من الالتزامات في مشروع الطلبات الرئيسية ، لذا فأنا أعرف ما يحب المشرفون رؤيته في العلاقات العامة والوظائف.

  1. يتم استخدام اسم المستخدم وكلمة المرور فقط في نوع معين من المنح التي تتطلبها. إذا تم استخدامها ، فقد تكون موجودة فقط في نص الطلب.

نعم ، بالنسبة للجزء الأول: نوع معين فقط من المنح يتطلب ذلك. لكن في الجزء الثاني حول إرسالها في نص الطلب ، تقول المواصفات:

تضمين بيانات اعتماد العميل في نص الطلب
استخدام المعلمتين غير مستحسن
ويجب أن يقتصر على العملاء غير القادرين على الاستفادة منها بشكل مباشر
نظام مصادقة HTTP الأساسي ...

لكن بالنسبة للخوادم ، فإنه يقرأ:

خادم التفويض قد يدعم بما في ذلك
بيانات اعتماد العميل في نص الطلب ...

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

أعتقد أن JonathanHuot محق بشأن النقطة الثانية.

مرحبًا ibuchanan ، الاقتباسات التي تشير إليها تستخدم المصطلح client credentials . يجب أن نكون حريصين للغاية على عدم الخلط بين العميل ومالك المورد (المستخدم الفعلي).

يتم شرح الأدوار بوضوح هنا rfc6749 # 1.1 .
يشير هذا client credentials إلى client_id و client_secret client credentials ويشير مالك المورد إلى username و password . هذه ليست قابلة للتبديل.

لذلك ، من خلال قراءة RFC بهذه الأدوار ، يجب أن يرسل العميل المتوافق client_id ، client_secret ) في HTTP Basic ويجب أن يرسل بيانات اعتماد المستخدم ( username ، password ) في نص الطلب (لا تقرأ بديلًا هنا أبدًا) ؛ انظر rfc6749 # 4.3.2 .

ترفض بعض الخوادم الطلب (400) إذا كان client_id في الطلب
هيئة. أعتقد أن الإعداد الافتراضي يجب أن يكون ما أوصت به المواصفات.

نعم. أعتقد أن العلاقات العامة الحالية لـ oauthlib تفي بالمخاوف المذكورة أعلاه - تسمح العلامة include_client_id صراحة بإرسال client_id أم لا.

من حيث requests_oauthlib ، هذا ما أفكر به:

  1. سيظهر username و password فقط في النص الأساسي (وليس كـ HTTP أساسي). إذا كان هذا السلوك مطلوبًا لتكامل خادم غير متوافق ، فيمكن للمنفذ إرسال وسيطة auth أو headers إلى fetch_token() .

  2. إن توفير client_id في المكان الصحيح أمر مزعج بعض الشيء ، لكنني أعتقد أن المنطق وحالات الاستخدام معطلة. هذا سيحتاج بالتأكيد بعض المراجعة.

سؤال لدي لJonathanHuot وibuchanan:

oauthlib OAuth2 Client و requests_oauthlib 's OAuth2Session لا تحتفظ بـ client_secret ويجب استدعائها مرارًا وتكرارًا. لم يكن هذا هو الحال في OAuth1 ، وأعتقد أن هذه كانت المشكلة الفعلية وراء # 370. لم يذكر RFC الحاجة إلى ذلك ، ولم أتمكن من العثور على أي تاريخ.

بالنسبة لي ، من المنطقي تمديد العميل بتخزين client_secret ، والبدء في إهمال اعتماد OAuth2Session على تمرير client_secret على fetch_token و request لصالح استخدام واحد الآن في العميل نفسه. (قد يعالج هذا أيضًا بعض التناقضات الأخرى التي تم الإبلاغ عنها في https://github.com/requests/requests-oauthlib/issues/264)

لقد غيرت قليلاً PR لـ oauthlib (# 593) لتوحيد متغيرات الاختبار لاسم المستخدم / كلمة المرور و client_id / client_secret. أعتقد أن هذا يجب أن يمنع الأخطاء من الخلط بين الاثنين في المستقبل.

التغيير المقترح لطلبات oauthlib: https://github.com/requests/requests-oauthlib/compare/master...jvanasco : fix-oauthlib_client_id

هذا واحد أكثر جذرية قليلاً ، لأنه بالنظر إلى الكود والاختبارات ، يبدو أن المكتبة كانت تحاول فقط جعل كل أنواع الأشياء تعمل بشكل لا ينبغي.

الإصلاح يقوم ببعض الأشياء:

  1. التحقق من username و password يحدث فقط لمثيلات LegacyApplicationClient - حيث يجب أن يكون هذا هو النوع الوحيد المطلوب (صحيح؟). يوجد قسم تحت الفحص يدمج اسم المستخدم / كلمة المرور في ملف kwargsict. لقد عفا عليها الزمن حاليًا ، لأن الاختبارات تشير إلى أن عملاء آخرين قد يرغبون في تمرير هذه المعلومات.

  2. تمت إعادة كتابة منطق التعامل مع رؤوس client_id / auth لضمان حدوث أنواع المصادقة الصحيحة في المكان الصحيح افتراضيًا. إذا أراد المستخدم فرض بيانات الاعتماد بطريقة أخرى ، فلا يزال ذلك ممكنًا.

  3. سؤال: هل هناك أي موقف لا يتم فيه تمرير client_secret ؟ لا يمكنني التفكير في أي شيء ، ولكن هناك العديد من تدفقات oAuth.

لذلك في إصدار طلبات oauthlib:

| include_client_id | auth | السلوك |
| ------------------- | --------------- | -------- |
| بلا (افتراضي) | بلا (افتراضي) | إنشاء كائن مصادقة باستخدام client_id . لا ترسل client_id في الجسم. هذا هو السلوك الافتراضي ، لأن RFC توصي به. |
| بلا (افتراضي) | الحاضر | استخدام كائن المصادقة. استدعاء oauthlib prepare_request_body مع include_client_id=False |
| خطأ | الحاضر | استخدام كائن المصادقة. استدعاء oauthlib prepare_request_body مع include_client_id=False |
| صحيح | الحاضر | استخدام كائن المصادقة. استدعاء oauthlib prepare_request_body مع include_client_id=True |
| صحيح | بلا (افتراضي) | إنشاء كائن مصادقة باستخدام client_id . استدعاء oauthlib prepare_request_body بـ include_client_id=True |
| خطأ | بلا (افتراضي) | إنشاء كائن مصادقة باستخدام client_id . استدعاء oauthlib prepare_request_body بـ include_client_id=False |

أو نص على خلاف ذلك:

  • إنشاء كائن المصادقة

    • لا ترسل معرف العميل في النص الأساسي:

    • (include_client_id = بلا ، مصادقة = بلا)

    • (include_client_id = خطأ ، المصادقة = بلا)

    • أرسل معرف العميل في النص الأساسي:

    • (include_client_id = صحيح ، المصادقة = بلا)

  • استخدام كائن مصادقة صريح

    • لا ترسل client_id في النص الأساسي:

    • (include_client_id = لا شيء ، المصادقة = authObject)

    • (include_client_id = خطأ ، auth = authObject)

    • أرسل client_id في النص الأساسي:

    • (include_client_id = صحيح ، المصادقة = authObject)

jvanasco : تبدو جيدة جدا على جانب oauthlib وطلبات oauthlib.

حول السؤال 3.:

يمكن أن يكون لديك عملاء عموميون بدون client_secret (أو فارغ ، هذا قريب من وجهة نظر RFC) ؛ لذلك يجب أن تدعم واجهة برمجة تطبيقات Python "لا سر".

غالبًا ما تكون حالة الاستخدام في العالم الحقيقي للتطبيقات الأصلية حيث تفضل استخدام رمز التفويض ، ولكن لا يمكنك ضمان الأمان حول الحفاظ على السر آمنًا ، لذلك ، إما أن تقبل client_id بدون client_secret (أو فارغ client_secret والذي يتطابق مع RFC) ؛ أو لديك أيضًا PKCE RFC آخر متاح (راجع https://oauth.net/2/pkce/). لكن الأخير لم يتم تنفيذه على جانب oauthlib ، حتى الآن.

شكرا. سأضيف بعض حالات الاختبار للتأكد من أنه يمكننا إرسال client_id بدون client_secret . نأسف لطرح الكثير من الأسئلة ، فهناك الكثير من التطبيقات الصحيحة الممكنة لهذه المواصفات (وحتى المزيد من التطبيقات المعطلة التي تحتاج إلى العمل).

JonathanHuot لا يدعم التطبيق الحالي إرسال سلسلة فارغة لـ client_secret . تمت إزالته في هذا المنطق https://github.com/oauthlib/oauthlib/blob/master/oauthlib/oauth2/rfc6749/parameters.py#L90 -L125 - تحديدًا السطر 122

يمكن أن يؤدي دعمها إلى إضافة شيء مثل هذا بعد هذا الروتين مباشرة:

if ('client_secret' in kwargs) and ('client_secret' not in params):
    if kwargs['client_secret'] == '':
        params.append((unicode_type('client_secret'), kwargs['client_secret']))

سيؤدي ذلك إلى إرسال سلسلة فارغة لـ client_secret عندما يكون السر عبارة عن سلسلة فارغة ، ولكن لا يتم إرسال client_secret إذا كانت القيمة None .

أعتقد أن الأمر يستحق دعم هذا ، لأنه إذا كان RFC يدعم أيًا من المتغيرين ... فمن المحتمل أن يكون هناك العديد من التطبيقات المعطلة التي تدعم متغيرًا واحدًا فقط.

تم إصلاح هذه المشكلة الأصلية في oauthlib. ومع ذلك ، لا يزال السلوك موجودًا حتى يتم إصلاح https://github.com/requests/requests-oauthlib/pull/331 .

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

JonathanHuot picture JonathanHuot  ·  10تعليقات

prudnikov picture prudnikov  ·  11تعليقات

JonathanHuot picture JonathanHuot  ·  33تعليقات

ggiill picture ggiill  ·  7تعليقات

polamayster picture polamayster  ·  19تعليقات