Oauthlib: Aplikasi web klien tidak lagi mengirim client_id

Dibuat pada 8 Sep 2018  ·  26Komentar  ·  Sumber: oauthlib/oauthlib

Saya menemukan regresi di master ketika digunakan dengan request/requests-oauthlib sejak https://github.com/oauthlib/oauthlib/issues/495 telah digabungkan. Ini terkait dengan pemberian otorisasi/aplikasi web saja.

Penggunaan dasar dari request-oauthlib adalah:

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

Namun, karena perubahan, client_id sesi diabaikan. Saya pikir https://github.com/oauthlib/oauthlib/pull/505 memperbaiki kasus penggunaan tetapi merusak yang lain. Kita harus mencari win-win solution.

panggilan kode request-oauthlib di https://github.com/requests/requests-oauthlib/blob/master/requests_oauthlib/oauth2_session.py#L196 -L198 dan masalah oauthlib di sini
https://github.com/oauthlib/oauthlib/blame/master/oauthlib/oauth2/rfc6749/clients/web_application.py#L128.

Bug Discussion OAuth2-Client

Komentar yang paling membantu

Tidak akan melihat bagaimana Anda ingin mengganti client_id dengan nilai yang berbeda sehingga akan memilih untuk mengajukan pengecualian jika berbeda.

Haruskah kita, sebagai tambahan, mencatat DeprecationWarning jika client_id diberikan sama sekali sebagai kwarg?

Semua 26 komentar

Pemikiran pertama saya adalah mengembalikan kembali perubahan pada prepare_request_body ke, secara default, menggunakan set self.client_id di WebApplicationClient konstruktor.
Kemudian, dokumen sebaris harus diubah secukupnya untuk menambahkan &client_id=xx ke prepare_request_body output.

Akhirnya, untuk mengganti perbaikan asli, saya akan menyarankan untuk menghapus client_id dari argumen, dan menambahkan argumen baru ke prepare_request_body seperti include_client=True/False untuk keduanya menambahkan client_id dan client_secret di dalam isi, atau tidak menyertakan keduanya.

Pikiran?

menyodok @Diaoul @skion @thedrow

Bagaimana dengan:

Saya akan menyarankan untuk menghapus client_id dari argumen, dan menambahkan argumen baru ke prepare_request_body seperti include_client=True/False untuk menambahkan client_id dan client_secret di badan, atau tidak menyertakan keduanya.

Terima kasih

Saya sebenarnya memicu masalah yang sama di salah satu pengujian saya, tetapi mengajukannya terhadap permintaan/oauthlib di sini: https://github.com/requests/requests-oauthlib/issues/330

Saya percaya masalahnya sebenarnya adalah kesalahan dari request_oauthlib. Dokumen mereka - sebenarnya contoh pertama di seluruh dokumen mereka saat Anda memuat halaman - mendukung penetapan client_id dalam konstruktor OAuth2Session . Logika pada baris 200 menarik client_id dari kwargs, tetapi tidak memiliki fallback untuk menariknya dari instance WebApplicationClient .

@jvanasco , masalah saat ini #585 dapat diperbaiki di request-oauthlib saja, atau dengan mengembalikan PR #505 oauthlib. Namun, tidak ada solusi yang akan memperbaiki perilaku yang disebutkan oleh @skion dalam komentarnya di https://github.com/oauthlib/oauthlib/pull/505#issuecomment -351221107

Menurut spesifikasi, parameter client_id harus dikirim untuk klien yang tidak diautentikasi, tetapi sebaiknya TIDAK dikirim dalam badan permintaan token untuk klien rahasia, karena dalam hal ini mekanisme yang lebih disukai untuk mengautentikasi klien adalah melalui HTTP Basic auth. Namun, kelas WebApplication selalu menyertakannya (yang merusak beberapa server) plus tidak menawarkan mekanisme untuk menghapusnya.

Oauthlib harus menyediakan cara yang elegan dan sederhana untuk request-oauthlib untuk menyelesaikan masalah. Jika kita dapat menemukan solusi dalam diskusi ini akan sangat bagus; karena itu pemblokir besar.

Apakah mengizinkan client_id=False di prepare_request_body() membantu, untuk menunjukkan bahwa client_id tidak akan dikirim? Meskipun demikian, itu akan mengarah pada keburukan ini di dekat baris 126 :

client_id = None if client_id=False else self.client_id

Aku mengerti.

Apakah ada unit-test yang ada untuk kapan client_id harus dikirim vs tidak? Jika tidak, apakah ada yang memiliki daftar yang dapat digunakan untuk membuatnya? Saya akan dengan senang hati mencoba memperbaiki ini dan meminta-oauthlib, karena itu memblokir beberapa pekerjaan saya sekarang.

@JonathanHuot

Saya akan menyarankan untuk menghapus client_id dari argumen, dan menambahkan argumen baru ke prepare_request_body seperti include_client=True/False untuk menambahkan client_id dan client_secret di badan, atau tidak menyertakan keduanya.

Membaca ini kembali, saya sebenarnya cukup menyukai saran Anda. Kita mungkin bisa melakukannya dengan cara yang tidak putus-putus, karena fungsinya sudah membutuhkan **kwargs .

Satu catatan:

untuk menambahkan client_id dan client_secret di badan

Karena ini tentang klien publik IIUC, menurut saya client_secret tidak terlibat; itu hanya client_id yang ditambahkan ke tubuh? Dalam hal ini saya juga akan mempertimbangkan untuk mengganti nama parameter baru menjadi include_client_id=True/False .

Dalam hal ini saya juga akan mempertimbangkan untuk mengganti nama parameter baru menjadi include_client_id=True/False.

Memang ! client_secret tidak terlibat karena tidak ada di WebApplicationClient .

@jvanasco , jika Anda ingin melakukan PR, saya pikir perubahannya harus:
1) Kembalikan https://github.com/oauthlib/oauthlib/pull/505
2) Ubah tanda tangan prepare_request_body() untuk menghapus client_id dan tambahkan include_client_id=True/False ( True (default): ia menambahkan self.client_id )

Kemudian, request-oauthlib akan memiliki pilihan di https://github.com/requests/requests-oauthlib/blob/master/requests_oauthlib/oauth2_session.py#L196-L211 untuk:
A) Sertakan client_id saja di badan

self._client.prepare_request_body(..)

B) Sertakan client_id dan client_secret dalam auth dan jangan sertakan mereka di badan (solusi pilihan RFC)

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

C) Sertakan client_id dan client_secret di badan (solusi alternatif RFC)

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

Saya akan menghasilkan PR untuk kedua proyek hari ini.

Saya sudah cukup banyak melakukan PR dan tes untuk OAuthlib. Saya punya pertanyaan meskipun ...

Haruskah client_id masih diperbolehkan sebagai kwarg? Ini sebagian untuk kompatibilitas mundur, tetapi juga untuk kasus tepi. Karena metode ini agak rusak, saya pikir mungkin layak membuatnya berfungsi sebagaimana dimaksud (seperti mengizinkannya di prepare_request_body untuk menimpa self.client_id) atau untuk meningkatkan Pengecualian pada penggunaan yang salah (seperti dalam menaikkan kesalahan jika client_id disediakan tetapi tidak cocok self.client_id ).

Tidak akan melihat bagaimana Anda ingin mengganti client_id dengan nilai yang berbeda sehingga akan memilih untuk mengajukan pengecualian jika berbeda.

Haruskah kita, sebagai tambahan, mencatat DeprecationWarning jika client_id diberikan sama sekali sebagai kwarg?

PR #593 dikirim. Ini menimbulkan DeprecationWarning ketika client_id dikirimkan, dan ValueError jika berbeda dari self.client_id . Ada juga tes baru yang memastikan kepatuhan dengan tiga skenario yang dirinci @JonathanHuot .

mengalami masalah pertama saya dengan kandidat PR permintaan-oauthlib saat saya menulis beberapa tes

Itu SELALU memanggil prepare_request_body dengan username=username, password=password . Ini sepertinya salah. Saya berharap seseorang di sini lebih akrab dengan RFC dan mengetahui jawaban berikut:

  1. haruskah username + password menjadi param di request.body ?
  2. jika username + password muncul di header HTTP Basic Auth, haruskah mereka diduplikasi di badan permintaan?
  3. Apakah mungkin memiliki username + password body params dan header HTTPBasicAuth dengan detail klien?

Terima kasih telah mengalami ini.

  1. username dan password harus selalu ada di badan permintaan. Mereka harus digunakan hanya untuk pemberian kata sandi alias warisan. Itu tidak boleh digunakan untuk hibah lain (implisit, kode, kredensial klien).
  2. HTTP Basic Auth adalah opsional untuk kredensial klien (disarankan untuk klien rahasia yaitu dengan client_secret ). Kredensial pengguna tidak boleh dalam HTTP Basic Auth.
  3. Ya

Terima kasih. Hanya untuk memperjelas dua hal, dan jangan ragu untuk berbicara dengan saya seperti saya berusia lima tahun. Saya ingin memastikan saya mendapatkan ini dan tes dengan benar:

  1. Nama pengguna dan kata sandi hanya digunakan dalam jenis hibah tertentu yang membutuhkannya. Jika digunakan, mereka mungkin hanya ada di badan permintaan.

Kecuali mereka secara eksplisit ditentukan, mereka tidak boleh ada, benar?

  1. Jika otentikasi dasar Http hanya untuk kredensial klien, maka permintaan-oauthlib yang ada seharusnya tidak memiliki blok yang menghasilkan otentikasi dasar dari kombo nama pengguna & kata sandi.

Maafkan saya yang bertele-tele dan terobsesi dengan detail kecil ini. Saya hanya ingin memastikan j mendapatkan perilaku yang benar dan dapat menulis tes yang memastikan kami tidak mendapatkan regresi lain.

@jvanasco , saya dapat memberi tahu tentang OAuth2 RFC, namun saya tidak yakin bagaimana requests-oauthlib dan flask-oauthlib cocok bersama.

  1. Ya

Benar.

  1. Ya, AFAIU seharusnya tidak memiliki blok ini https://github.com/requests/requests-oauthlib/blob/master/requests_oauthlib/oauth2_session.py#L207 -L211.

Ini pemahaman saya, namun alangkah baiknya jika disandingkan dengan kenyataan di lapangan; yaitu request-oauthlib dan pengalaman penyedia publik yang berbeda. Beberapa diskusi permintaan-oauthlib https://github.com/requests/requests-oauthlib/issues/218 , https://github.com/requests/requests-oauthlib/issues/211 , https://github.com/requests /requests-oauthlib/issues/264 , sudah terjadi.

Saya percaya mereka memiliki kebingungan antara client password dan client secret yang sebenarnya adalah dua kata untuk hal yang sama persis.
Jika kita mengikuti alasan di balik https://github.com/requests/requests-oauthlib/pull/206 , konten PR seharusnya tidak pernah seperti menambahkan HTTPAuth(username, password) tetapi seharusnya HTTPAuth(client_id, client_secret (kata sandi klien).

Poke @Lukasa , @chaosct , @ibuchanan yang berpartisipasi dalam diskusi request-oauthlib.

Besar! Terima kasih banyak. Saya pikir itulah yang sedang terjadi tetapi ingin mengkonfirmasi.

Saya pikir saya tahu bagaimana saya ingin menyusun hal-hal permintaan sekarang. Saya memiliki beberapa komit pada proyek permintaan utama, jadi saya tahu apa yang ingin dilihat pengelola dalam PR dan fungsionalitas.

  1. Nama pengguna dan kata sandi hanya digunakan dalam jenis hibah tertentu yang membutuhkannya. Jika digunakan, mereka mungkin hanya ada di badan permintaan.

Ya, untuk bagian pertama: hanya jenis hibah tertentu yang membutuhkannya. Tetapi pada bagian ke-2 tentang mengirimnya di badan permintaan, spesifikasinya mengatakan:

Menyertakan kredensial klien di badan permintaan
menggunakan dua parameter TIDAK DIREKOMENDASIKAN
dan HARUS terbatas pada klien yang tidak dapat langsung memanfaatkan
skema otentikasi HTTP Basic...

Tetapi untuk server, itu berbunyi:

Server otorisasi MUNGKIN mendukung termasuk
kredensial klien di badan permintaan...

Klien yang patuh, tidak akan mengirim kredensial di badan permintaan.
Namun, untuk beberapa server yang diimplementasikan sebagian, mereka hanya akan menerimanya di badan permintaan.
Jika saya ingat dengan benar, PR saya memecahkan kebingungan ini dengan menambahkan header auth,
jadi klien mengirim keduanya.

Saya percaya @JonathanHuot benar tentang poin ke-2.

Hai @ibuchanan , kutipan yang Anda maksud menggunakan istilah client credentials . Kita harus sangat berhati-hati untuk tidak mencampuradukkan klien dengan pemilik sumber daya (pengguna sebenarnya).

Peran dijelaskan dengan jelas di sini rfc6749#1.1 .
client credentials merujuk ke client_id dan client_secret dan pemilik sumber daya merujuk ke username dan password . Itu tidak bisa dipertukarkan.

Jadi, dengan membaca RFC dengan peran tersebut berarti bahwa klien yang patuh HARUS mengirim kredensial klien ( client_id , client_secret ) di HTTP Basic dan HARUS mengirim kredensial pengguna ( username , password ) di badan permintaan (jangan pernah membaca alternatif di sini); lihat rfc6749#4.3.2 .

Beberapa server menolak permintaan (400) jika client_id ada dalam permintaan
tubuh. Saya pikir defaultnya harus seperti yang direkomendasikan oleh spec.

Oke. Saya pikir PR saat ini untuk oauthlib memenuhi masalah di atas - flag include_client_id secara eksplisit memungkinkan client_id dikirim atau tidak.

dalam hal requests_oauthlib , inilah yang saya pikirkan:

  1. username dan password hanya akan muncul di badan (bukan sebagai HTTP Basic). Jika perilaku itu diperlukan untuk integrasi server yang tidak sesuai, pelaksana dapat mengirimkan argumen auth atau headers ke fetch_token() .

  2. memasok client_id di tempat yang benar agak mengganggu, tapi saya pikir saya memiliki logika dan kasus penggunaan. ini pasti akan membutuhkan beberapa tinjauan.

Sebuah pertanyaan yang saya miliki untuk @JonathanHuot dan @ibuchanan :

oauthlib 's OAuth2 Client dan requests_oauthlib ' s OAuth2Session tidak menjaga client_secret dan harus berulang kali meminta itu. Ini tidak terjadi di OAuth1, dan saya pikir ini adalah masalah sebenarnya di balik #370. RFC tidak menyebutkan perlunya ini, dan saya tidak dapat menemukan riwayat apa pun.

Bagi saya, masuk akal untuk memperluas Klien dengan menyimpan client_secret , dan mulai menghentikan ketergantungan OAuth2Session dengan meneruskan client_secret pada fetch_token dan request untuk menggunakan yang sekarang ada di Klien itu sendiri. (ini juga akan mengatasi beberapa inkonsistensi lain yang dilaporkan di https://github.com/requests/requests-oauthlib/issues/264 )

Saya telah sedikit mengubah PR untuk oauthlib (#593) untuk membakukan variabel uji untuk nama pengguna/kata sandi dan client_id/client_secret. Saya pikir itu harus mencegah kesalahan dari kebingungan antara keduanya di masa depan.

Perubahan yang diusulkan untuk request-oauthlib : https://github.com/requests/requests-oauthlib/compare/master...jvanasco :fix-oauthlib_client_id

Yang ini sedikit lebih drastis, karena melihat kode dan pengujian, sepertinya perpustakaan hanya mencoba membuat segala macam hal berfungsi yang tidak seharusnya.

Perbaikan melakukan beberapa hal:

  1. Memeriksa username dan password hanya terjadi untuk instance LegacyApplicationClient -- karena itu adalah satu-satunya jenis yang diperlukan (benar?). Ada bagian di bawah centang yang menggabungkan nama pengguna/kata sandi ke dalam dict kwargs. Saat ini sudah ketinggalan zaman, karena tes menyarankan klien lain mungkin ingin meneruskan informasi ini.

  2. Logika untuk menangani header client_id/auth ditulis ulang untuk memastikan jenis auth yang tepat terjadi di tempat yang tepat secara default. Jika pengguna ingin memaksa kredensial dengan cara lain, itu masih mungkin.

  3. Pertanyaan: Apakah ada situasi di mana client_secret tidak akan dilewati? Saya tidak dapat memikirkannya, tetapi ada banyak aliran oAuth.

Jadi dalam versi request-oauthlib:

| include_client_id | auth | perilaku |
| ------------------- | --------------- | -------- |
| Tidak ada (Bawaan) | Tidak ada (Bawaan) | buat objek Auth dengan client_id . Jangan kirim client_id di badan. Ini adalah perilaku default, karena RFC merekomendasikannya. |
| Tidak ada (Bawaan) | hadir | menggunakan objek Auth. aktifkan prepare_request_body oauthlib dengan include_client_id=False |
| Salah | hadir | menggunakan objek Auth. aktifkan prepare_request_body oauthlib dengan include_client_id=False |
| Benar | hadir | menggunakan objek Auth. aktifkan prepare_request_body oauthlib dengan include_client_id=True |
| Benar | Tidak ada (Bawaan) | buat objek Auth dengan client_id . aktifkan prepare_request_body oauthlib dengan include_client_id=True |
| Salah | Tidak ada (Bawaan) | buat objek Auth dengan client_id . aktifkan prepare_request_body oauthlib dengan include_client_id=False |

atau dinyatakan lain:

  • buat objek autentik

    • jangan kirim id klien di badan:

    • (include_client_id=Tidak ada, auth=Tidak ada)

    • (include_client_id=Salah, auth=Tidak ada)

    • kirim id klien di badan:

    • (include_client_id=Benar, auth=Tidak ada)

  • gunakan objek auth eksplisit

    • jangan kirim client_id di badan:

    • (include_client_id=Tidak ada, auth=authObject)

    • (include_client_id=False, auth=authObject)

    • kirim client_id di badan:

    • (include_client_id=Benar, auth=authObject)

@jvanasco : terlihat sangat bagus di sisi oauthlib dan request-oauthlib.

Tentang 3. pertanyaan Anda:

Anda dapat memiliki klien publik tanpa client_secret (atau kosong, yang mendekati sudut pandang RFC); jadi python API harus mendukung "no secret".

Kasus penggunaan dunia nyata sering kali untuk aplikasi asli di mana Anda lebih suka menggunakan kode otorisasi, tetapi Anda tidak dapat menjamin keamanan di sekitar menjaga rahasia tetap aman, jadi, Anda menerima client_id tanpa client_secret (atau kosongkan client_secret yang identik untuk RFC); atau Anda juga memiliki PKCE RFC lain yang tersedia (lihat https://oauth.net/2/pkce/ ). Tetapi yang terakhir belum diimplementasikan di sisi oauthlib .

Terima kasih. saya akan menambahkan beberapa kasus uji untuk memastikan kami dapat mengirimkan client_id tanpa client_secret . Maaf telah mengajukan begitu banyak pertanyaan, ada begitu banyak kemungkinan implementasi yang benar dari spesifikasi ini (dan bahkan lebih banyak lagi implementasi yang rusak yang perlu bekerja).

@JonathanHuot implementasi yang ada tidak mendukung pengiriman string kosong untuk client_secret . Itu dihapus dalam logika ini https://github.com/oauthlib/oauthlib/blob/master/oauthlib/oauth2/rfc6749/parameters.py#L90 -L125 -- khususnya baris 122

Mendukungnya dapat menambahkan sesuatu seperti ini tepat setelah rutinitas itu:

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

Itu akan mengirim string kosong untuk client_secret ketika rahasianya adalah string kosong, tetapi tidak mengirim client_secret jika nilainya None .

Saya pikir ini layak untuk didukung, karena jika RFC mendukung salah satu dari dua varian... kemungkinan akan banyak implementasi yang rusak yang hanya mendukung satu varian.

Masalah asli ini diperbaiki di oauthlib. Namun perilaku itu masih ada sampai https://github.com/requests/requests-oauthlib/pull/331 diperbaiki.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

JonathanHuot picture JonathanHuot  ·  33Komentar

ryarnyah picture ryarnyah  ·  3Komentar

ib-lundgren picture ib-lundgren  ·  21Komentar

polamayster picture polamayster  ·  19Komentar

thedrow picture thedrow  ·  31Komentar