test_oauth2_complete_view.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. import responses
  2. from django.contrib.auth import get_user_model
  3. from django.urls import reverse
  4. from responses.matchers import header_matcher, urlencoded_params_matcher
  5. from ...conf.test import override_dynamic_settings
  6. from ...test import assert_contains
  7. from ...users.bans import ban_ip, ban_user
  8. from ..client import SESSION_STATE
  9. from ..models import Subject
  10. User = get_user_model()
  11. def test_oauth2_complete_view_returns_404_if_oauth_is_disabled(
  12. client, dynamic_settings
  13. ):
  14. assert dynamic_settings.enable_oauth2_client is False
  15. response = client.get(reverse("misago:oauth2-complete"))
  16. assert response.status_code == 404
  17. def test_oauth2_complete_view_returns_error_404_if_user_ip_is_banned_and_oauth_is_disabled(
  18. client, dynamic_settings
  19. ):
  20. ban_ip("127.*", "Ya got banned!")
  21. assert dynamic_settings.enable_oauth2_client is False
  22. response = client.get(reverse("misago:oauth2-complete"))
  23. assert response.status_code == 404
  24. @override_dynamic_settings(
  25. enable_oauth2_client=True,
  26. oauth2_client_id="clientid123",
  27. oauth2_scopes="scopes",
  28. oauth2_login_url="https://example.com/oauth2/login",
  29. )
  30. def test_oauth2_complete_view_returns_error_403_if_user_ip_is_banned(
  31. client, dynamic_settings
  32. ):
  33. ban_ip("127.*", "Ya got banned!")
  34. assert dynamic_settings.enable_oauth2_client is True
  35. response = client.get(reverse("misago:oauth2-complete"))
  36. assert_contains(response, "Ya got banned", 403)
  37. @override_dynamic_settings(
  38. enable_oauth2_client=True,
  39. oauth2_client_id="clientid123",
  40. oauth2_scopes="scopes",
  41. oauth2_login_url="https://example.com/oauth2/login",
  42. )
  43. def test_oauth2_complete_view_returns_error_400_if_user_canceled_sign_in(
  44. client, dynamic_settings
  45. ):
  46. assert dynamic_settings.enable_oauth2_client is True
  47. response = client.get("%s?error=access_denied" % reverse("misago:oauth2-complete"))
  48. assert_contains(response, "The OAuth2 process was canceled by the provider.", 400)
  49. @override_dynamic_settings(
  50. enable_oauth2_client=True,
  51. oauth2_client_id="clientid123",
  52. oauth2_scopes="scopes",
  53. oauth2_login_url="https://example.com/oauth2/login",
  54. )
  55. def test_oauth2_complete_view_returns_error_400_if_state_is_not_set(
  56. client, dynamic_settings
  57. ):
  58. assert dynamic_settings.enable_oauth2_client is True
  59. response = client.get(reverse("misago:oauth2-complete"))
  60. assert_contains(response, "OAuth2 session is missing state.", 400)
  61. @override_dynamic_settings(
  62. enable_oauth2_client=True,
  63. oauth2_client_id="clientid123",
  64. oauth2_scopes="scopes",
  65. oauth2_login_url="https://example.com/oauth2/login",
  66. )
  67. def test_oauth2_complete_view_returns_error_400_if_state_is_invalid(
  68. client, dynamic_settings
  69. ):
  70. assert dynamic_settings.enable_oauth2_client is True
  71. session = client.session
  72. session[SESSION_STATE] = "state123"
  73. session.save()
  74. response = client.get(
  75. "%s?state=invalid&code=1234" % reverse("misago:oauth2-complete")
  76. )
  77. assert_contains(
  78. response,
  79. "OAuth2 state sent by the provider did not match one in the session.",
  80. 400,
  81. )
  82. @override_dynamic_settings(
  83. enable_oauth2_client=True,
  84. oauth2_client_id="clientid123",
  85. oauth2_scopes="scopes",
  86. oauth2_login_url="https://example.com/oauth2/login",
  87. )
  88. def test_oauth2_complete_view_returns_error_400_if_code_is_missing(
  89. client, dynamic_settings
  90. ):
  91. assert dynamic_settings.enable_oauth2_client is True
  92. session = client.session
  93. session[SESSION_STATE] = "state123"
  94. session.save()
  95. response = client.get("%s?state=state123&code=" % reverse("misago:oauth2-complete"))
  96. assert_contains(
  97. response,
  98. "OAuth2 authorization code was not sent by the provider.",
  99. 400,
  100. )
  101. TEST_SETTINGS = {
  102. "enable_oauth2_client": True,
  103. "oauth2_client_id": "oauth2_client_id",
  104. "oauth2_client_secret": "oauth2_client_secret",
  105. "oauth2_login_url": "https://example.com/oauth2/login",
  106. "oauth2_token_url": "https://example.com/oauth2/token",
  107. "oauth2_token_method": "POST",
  108. "oauth2_json_token_path": "token.bearer",
  109. "oauth2_user_url": "https://example.com/oauth2/user",
  110. "oauth2_user_method": "POST",
  111. "oauth2_user_token_name": "Authorization",
  112. "oauth2_user_token_location": "HEADER_BEARER",
  113. "oauth2_send_welcome_email": True,
  114. "oauth2_json_id_path": "id",
  115. "oauth2_json_name_path": "profile.name",
  116. "oauth2_json_email_path": "profile.email",
  117. }
  118. @responses.activate
  119. @override_dynamic_settings(**TEST_SETTINGS)
  120. def test_oauth2_complete_view_creates_new_user(client, dynamic_settings, mailoutbox):
  121. assert dynamic_settings.enable_oauth2_client is True
  122. code_grant = "12345grant"
  123. session_state = "12345state"
  124. access_token = "12345token"
  125. session = client.session
  126. session[SESSION_STATE] = session_state
  127. session.save()
  128. responses.post(
  129. "https://example.com/oauth2/token",
  130. json={
  131. "token": {
  132. "bearer": access_token,
  133. },
  134. },
  135. match=[
  136. urlencoded_params_matcher(
  137. {
  138. "grant_type": "authorization_code",
  139. "client_id": "oauth2_client_id",
  140. "client_secret": "oauth2_client_secret",
  141. "redirect_uri": "http://testserver/oauth2/complete/",
  142. "code": code_grant,
  143. },
  144. ),
  145. ],
  146. )
  147. responses.post(
  148. "https://example.com/oauth2/user",
  149. json={
  150. "id": 1234,
  151. "profile": {
  152. "name": "John Doe",
  153. "email": "john@example.com",
  154. },
  155. },
  156. match=[
  157. header_matcher({"Authorization": f"Bearer {access_token}"}),
  158. ],
  159. )
  160. response = client.get(
  161. "%s?state=%s&code=%s"
  162. % (
  163. reverse("misago:oauth2-complete"),
  164. session_state,
  165. code_grant,
  166. )
  167. )
  168. assert response.status_code == 302
  169. # User and subject are created
  170. subject = Subject.objects.get(sub="1234")
  171. user = User.objects.get_by_email("john@example.com")
  172. assert subject.user_id == user.id
  173. assert user.username == "John_Doe"
  174. assert user.slug == "john-doe"
  175. assert user.email == "john@example.com"
  176. assert user.requires_activation == User.ACTIVATION_NONE
  177. # User is authenticated
  178. auth_api = client.get(reverse("misago:api:auth")).json()
  179. assert auth_api["id"] == user.id
  180. # User welcome e-mail is sent
  181. assert len(mailoutbox) == 1
  182. assert mailoutbox[0].subject == "Welcome on Misago forums!"
  183. TEST_SETTINGS_EMAIL_DISABLED = TEST_SETTINGS.copy()
  184. TEST_SETTINGS_EMAIL_DISABLED["oauth2_send_welcome_email"] = False
  185. @responses.activate
  186. @override_dynamic_settings(**TEST_SETTINGS_EMAIL_DISABLED)
  187. def test_oauth2_complete_view_doesnt_send_welcome_mail_if_option_is_disabled(
  188. client, dynamic_settings, mailoutbox
  189. ):
  190. assert dynamic_settings.enable_oauth2_client is True
  191. code_grant = "12345grant"
  192. session_state = "12345state"
  193. access_token = "12345token"
  194. session = client.session
  195. session[SESSION_STATE] = session_state
  196. session.save()
  197. responses.post(
  198. "https://example.com/oauth2/token",
  199. json={
  200. "token": {
  201. "bearer": access_token,
  202. },
  203. },
  204. match=[
  205. urlencoded_params_matcher(
  206. {
  207. "grant_type": "authorization_code",
  208. "client_id": "oauth2_client_id",
  209. "client_secret": "oauth2_client_secret",
  210. "redirect_uri": "http://testserver/oauth2/complete/",
  211. "code": code_grant,
  212. },
  213. ),
  214. ],
  215. )
  216. responses.post(
  217. "https://example.com/oauth2/user",
  218. json={
  219. "id": 1234,
  220. "profile": {
  221. "name": "John Doe",
  222. "email": "john@example.com",
  223. },
  224. },
  225. match=[
  226. header_matcher({"Authorization": f"Bearer {access_token}"}),
  227. ],
  228. )
  229. response = client.get(
  230. "%s?state=%s&code=%s"
  231. % (
  232. reverse("misago:oauth2-complete"),
  233. session_state,
  234. code_grant,
  235. )
  236. )
  237. assert response.status_code == 302
  238. # User and subject are created
  239. subject = Subject.objects.get(sub="1234")
  240. user = User.objects.get_by_email("john@example.com")
  241. assert subject.user_id == user.id
  242. # User is authenticated
  243. auth_api = client.get(reverse("misago:api:auth")).json()
  244. assert auth_api["id"] == user.id
  245. # User welcome e-mail is not sent
  246. assert len(mailoutbox) == 0
  247. TEST_SETTINGS_EXTRA_TOKEN_HEADERS = TEST_SETTINGS.copy()
  248. TEST_SETTINGS_EXTRA_TOKEN_HEADERS[
  249. "oauth2_token_extra_headers"
  250. ] = """
  251. Accept: application/json
  252. API-Version: 2.1.3.7
  253. """.strip()
  254. @responses.activate
  255. @override_dynamic_settings(**TEST_SETTINGS_EXTRA_TOKEN_HEADERS)
  256. def test_oauth2_complete_view_includes_extra_headers_in_token_request(
  257. client, dynamic_settings, mailoutbox
  258. ):
  259. assert dynamic_settings.enable_oauth2_client is True
  260. code_grant = "12345grant"
  261. session_state = "12345state"
  262. access_token = "12345token"
  263. session = client.session
  264. session[SESSION_STATE] = session_state
  265. session.save()
  266. responses.post(
  267. "https://example.com/oauth2/token",
  268. json={
  269. "token": {
  270. "bearer": access_token,
  271. },
  272. },
  273. match=[
  274. urlencoded_params_matcher(
  275. {
  276. "grant_type": "authorization_code",
  277. "client_id": "oauth2_client_id",
  278. "client_secret": "oauth2_client_secret",
  279. "redirect_uri": "http://testserver/oauth2/complete/",
  280. "code": code_grant,
  281. },
  282. ),
  283. header_matcher(
  284. {
  285. "Accept": "application/json",
  286. "API-Version": "2.1.3.7",
  287. }
  288. ),
  289. ],
  290. )
  291. responses.post(
  292. "https://example.com/oauth2/user",
  293. json={
  294. "id": 1234,
  295. "profile": {
  296. "name": "John Doe",
  297. "email": "john@example.com",
  298. },
  299. },
  300. match=[
  301. header_matcher({"Authorization": f"Bearer {access_token}"}),
  302. ],
  303. )
  304. response = client.get(
  305. "%s?state=%s&code=%s"
  306. % (
  307. reverse("misago:oauth2-complete"),
  308. session_state,
  309. code_grant,
  310. )
  311. )
  312. assert response.status_code == 302
  313. # User and subject are created
  314. subject = Subject.objects.get(sub="1234")
  315. user = User.objects.get_by_email("john@example.com")
  316. assert subject.user_id == user.id
  317. # User is authenticated
  318. auth_api = client.get(reverse("misago:api:auth")).json()
  319. assert auth_api["id"] == user.id
  320. TEST_SETTINGS_EXTRA_USER_HEADERS = TEST_SETTINGS.copy()
  321. TEST_SETTINGS_EXTRA_USER_HEADERS[
  322. "oauth2_user_extra_headers"
  323. ] = """
  324. X-Header: its-a-test
  325. API-Version: 2.1.3.7
  326. """.strip()
  327. @responses.activate
  328. @override_dynamic_settings(**TEST_SETTINGS_EXTRA_USER_HEADERS)
  329. def test_oauth2_complete_view_includes_extra_headers_in_user_request(
  330. client, dynamic_settings, mailoutbox
  331. ):
  332. assert dynamic_settings.enable_oauth2_client is True
  333. code_grant = "12345grant"
  334. session_state = "12345state"
  335. access_token = "12345token"
  336. session = client.session
  337. session[SESSION_STATE] = session_state
  338. session.save()
  339. responses.post(
  340. "https://example.com/oauth2/token",
  341. json={
  342. "token": {
  343. "bearer": access_token,
  344. },
  345. },
  346. match=[
  347. urlencoded_params_matcher(
  348. {
  349. "grant_type": "authorization_code",
  350. "client_id": "oauth2_client_id",
  351. "client_secret": "oauth2_client_secret",
  352. "redirect_uri": "http://testserver/oauth2/complete/",
  353. "code": code_grant,
  354. },
  355. ),
  356. ],
  357. )
  358. responses.post(
  359. "https://example.com/oauth2/user",
  360. json={
  361. "id": 1234,
  362. "profile": {
  363. "name": "John Doe",
  364. "email": "john@example.com",
  365. },
  366. },
  367. match=[
  368. header_matcher(
  369. {
  370. "Authorization": f"Bearer {access_token}",
  371. "X-Header": "its-a-test",
  372. "API-Version": "2.1.3.7",
  373. }
  374. ),
  375. ],
  376. )
  377. response = client.get(
  378. "%s?state=%s&code=%s"
  379. % (
  380. reverse("misago:oauth2-complete"),
  381. session_state,
  382. code_grant,
  383. )
  384. )
  385. assert response.status_code == 302
  386. # User and subject are created
  387. subject = Subject.objects.get(sub="1234")
  388. user = User.objects.get_by_email("john@example.com")
  389. assert subject.user_id == user.id
  390. # User is authenticated
  391. auth_api = client.get(reverse("misago:api:auth")).json()
  392. assert auth_api["id"] == user.id
  393. @responses.activate
  394. @override_dynamic_settings(**TEST_SETTINGS)
  395. def test_oauth2_complete_view_updates_existing_user(
  396. user, client, dynamic_settings, mailoutbox
  397. ):
  398. assert dynamic_settings.enable_oauth2_client is True
  399. Subject.objects.create(sub="1234", user=user)
  400. code_grant = "12345grant"
  401. session_state = "12345state"
  402. access_token = "12345token"
  403. session = client.session
  404. session[SESSION_STATE] = session_state
  405. session.save()
  406. responses.post(
  407. "https://example.com/oauth2/token",
  408. json={
  409. "token": {
  410. "bearer": access_token,
  411. },
  412. },
  413. match=[
  414. urlencoded_params_matcher(
  415. {
  416. "grant_type": "authorization_code",
  417. "client_id": "oauth2_client_id",
  418. "client_secret": "oauth2_client_secret",
  419. "redirect_uri": "http://testserver/oauth2/complete/",
  420. "code": code_grant,
  421. },
  422. ),
  423. ],
  424. )
  425. responses.post(
  426. "https://example.com/oauth2/user",
  427. json={
  428. "id": 1234,
  429. "profile": {
  430. "name": "John Doe",
  431. "email": "john@example.com",
  432. },
  433. },
  434. match=[
  435. header_matcher({"Authorization": f"Bearer {access_token}"}),
  436. ],
  437. )
  438. response = client.get(
  439. "%s?state=%s&code=%s"
  440. % (
  441. reverse("misago:oauth2-complete"),
  442. session_state,
  443. code_grant,
  444. )
  445. )
  446. assert response.status_code == 302
  447. # User is updated
  448. user.refresh_from_db()
  449. assert user.username == "John_Doe"
  450. assert user.slug == "john-doe"
  451. assert user.email == "john@example.com"
  452. # User is authenticated
  453. auth_api = client.get(reverse("misago:api:auth")).json()
  454. assert auth_api["id"] == user.id
  455. # User welcome e-mail is not sent
  456. assert len(mailoutbox) == 0
  457. @responses.activate
  458. @override_dynamic_settings(**TEST_SETTINGS)
  459. def test_oauth2_complete_view_returns_error_400_if_code_grant_is_rejected(
  460. client, dynamic_settings
  461. ):
  462. assert dynamic_settings.enable_oauth2_client is True
  463. code_grant = "12345grant"
  464. session_state = "12345state"
  465. session = client.session
  466. session[SESSION_STATE] = session_state
  467. session.save()
  468. responses.post(
  469. "https://example.com/oauth2/token",
  470. json={
  471. "error": "Permission denied",
  472. },
  473. status=403,
  474. match=[
  475. urlencoded_params_matcher(
  476. {
  477. "grant_type": "authorization_code",
  478. "client_id": "oauth2_client_id",
  479. "client_secret": "oauth2_client_secret",
  480. "redirect_uri": "http://testserver/oauth2/complete/",
  481. "code": code_grant,
  482. },
  483. ),
  484. ],
  485. )
  486. response = client.get(
  487. "%s?state=%s&code=%s"
  488. % (
  489. reverse("misago:oauth2-complete"),
  490. session_state,
  491. code_grant,
  492. )
  493. )
  494. assert_contains(
  495. response,
  496. "The OAuth2 provider responded with error for an access token request.",
  497. 400,
  498. )
  499. @responses.activate
  500. @override_dynamic_settings(**TEST_SETTINGS)
  501. def test_oauth2_complete_view_returns_error_400_if_access_token_is_rejected(
  502. user, client, dynamic_settings
  503. ):
  504. assert dynamic_settings.enable_oauth2_client is True
  505. Subject.objects.create(sub="1234", user=user)
  506. code_grant = "12345grant"
  507. session_state = "12345state"
  508. access_token = "12345token"
  509. session = client.session
  510. session[SESSION_STATE] = session_state
  511. session.save()
  512. responses.post(
  513. "https://example.com/oauth2/token",
  514. json={
  515. "token": {
  516. "bearer": access_token,
  517. },
  518. },
  519. match=[
  520. urlencoded_params_matcher(
  521. {
  522. "grant_type": "authorization_code",
  523. "client_id": "oauth2_client_id",
  524. "client_secret": "oauth2_client_secret",
  525. "redirect_uri": "http://testserver/oauth2/complete/",
  526. "code": code_grant,
  527. },
  528. ),
  529. ],
  530. )
  531. responses.post(
  532. "https://example.com/oauth2/user",
  533. json={
  534. "error": "Permission denied",
  535. },
  536. status=403,
  537. )
  538. response = client.get(
  539. "%s?state=%s&code=%s"
  540. % (
  541. reverse("misago:oauth2-complete"),
  542. session_state,
  543. code_grant,
  544. )
  545. )
  546. assert_contains(
  547. response,
  548. "The OAuth2 provider responded with error for user profile request.",
  549. 400,
  550. )
  551. @responses.activate
  552. @override_dynamic_settings(**TEST_SETTINGS)
  553. def test_oauth2_complete_view_returns_error_400_if_user_email_was_missing(
  554. user, client, dynamic_settings
  555. ):
  556. assert dynamic_settings.enable_oauth2_client is True
  557. Subject.objects.create(sub="1234", user=user)
  558. code_grant = "12345grant"
  559. session_state = "12345state"
  560. access_token = "12345token"
  561. session = client.session
  562. session[SESSION_STATE] = session_state
  563. session.save()
  564. responses.post(
  565. "https://example.com/oauth2/token",
  566. json={
  567. "token": {
  568. "bearer": access_token,
  569. },
  570. },
  571. match=[
  572. urlencoded_params_matcher(
  573. {
  574. "grant_type": "authorization_code",
  575. "client_id": "oauth2_client_id",
  576. "client_secret": "oauth2_client_secret",
  577. "redirect_uri": "http://testserver/oauth2/complete/",
  578. "code": code_grant,
  579. },
  580. ),
  581. ],
  582. )
  583. responses.post(
  584. "https://example.com/oauth2/user",
  585. json={
  586. "id": 1234,
  587. "profile": {
  588. "name": "John Doe",
  589. },
  590. },
  591. match=[
  592. header_matcher({"Authorization": f"Bearer {access_token}"}),
  593. ],
  594. )
  595. response = client.get(
  596. "%s?state=%s&code=%s"
  597. % (
  598. reverse("misago:oauth2-complete"),
  599. session_state,
  600. code_grant,
  601. )
  602. )
  603. assert_contains(response, "Enter a valid email address.", 400)
  604. @responses.activate
  605. @override_dynamic_settings(**TEST_SETTINGS)
  606. def test_oauth2_complete_view_returns_error_400_if_user_email_was_invalid(
  607. user, client, dynamic_settings
  608. ):
  609. assert dynamic_settings.enable_oauth2_client is True
  610. Subject.objects.create(sub="1234", user=user)
  611. code_grant = "12345grant"
  612. session_state = "12345state"
  613. access_token = "12345token"
  614. session = client.session
  615. session[SESSION_STATE] = session_state
  616. session.save()
  617. responses.post(
  618. "https://example.com/oauth2/token",
  619. json={
  620. "token": {
  621. "bearer": access_token,
  622. },
  623. },
  624. match=[
  625. urlencoded_params_matcher(
  626. {
  627. "grant_type": "authorization_code",
  628. "client_id": "oauth2_client_id",
  629. "client_secret": "oauth2_client_secret",
  630. "redirect_uri": "http://testserver/oauth2/complete/",
  631. "code": code_grant,
  632. },
  633. ),
  634. ],
  635. )
  636. responses.post(
  637. "https://example.com/oauth2/user",
  638. json={
  639. "id": 1234,
  640. "profile": {
  641. "name": "John Doe",
  642. "email": "invalid",
  643. },
  644. },
  645. match=[
  646. header_matcher({"Authorization": f"Bearer {access_token}"}),
  647. ],
  648. )
  649. response = client.get(
  650. "%s?state=%s&code=%s"
  651. % (
  652. reverse("misago:oauth2-complete"),
  653. session_state,
  654. code_grant,
  655. )
  656. )
  657. assert_contains(response, "Enter a valid email address.", 400)
  658. @responses.activate
  659. @override_dynamic_settings(**TEST_SETTINGS)
  660. def test_oauth2_complete_view_returns_error_400_if_user_data_causes_integrity_error(
  661. user, client, dynamic_settings
  662. ):
  663. assert dynamic_settings.enable_oauth2_client is True
  664. code_grant = "12345grant"
  665. session_state = "12345state"
  666. access_token = "12345token"
  667. session = client.session
  668. session[SESSION_STATE] = session_state
  669. session.save()
  670. responses.post(
  671. "https://example.com/oauth2/token",
  672. json={
  673. "token": {
  674. "bearer": access_token,
  675. },
  676. },
  677. match=[
  678. urlencoded_params_matcher(
  679. {
  680. "grant_type": "authorization_code",
  681. "client_id": "oauth2_client_id",
  682. "client_secret": "oauth2_client_secret",
  683. "redirect_uri": "http://testserver/oauth2/complete/",
  684. "code": code_grant,
  685. },
  686. ),
  687. ],
  688. )
  689. responses.post(
  690. "https://example.com/oauth2/user",
  691. json={
  692. "id": 1234,
  693. "profile": {
  694. "name": "John Doe",
  695. "email": user.email,
  696. },
  697. },
  698. match=[
  699. header_matcher({"Authorization": f"Bearer {access_token}"}),
  700. ],
  701. )
  702. response = client.get(
  703. "%s?state=%s&code=%s"
  704. % (
  705. reverse("misago:oauth2-complete"),
  706. session_state,
  707. code_grant,
  708. )
  709. )
  710. assert_contains(response, "This e-mail address is not available.", 400)
  711. @responses.activate
  712. @override_dynamic_settings(**TEST_SETTINGS)
  713. def test_oauth2_complete_view_updates_deactivated_user_but_returns_error_400(
  714. user, client, dynamic_settings, mailoutbox
  715. ):
  716. assert dynamic_settings.enable_oauth2_client is True
  717. Subject.objects.create(sub="1234", user=user)
  718. user.is_active = False
  719. user.save()
  720. code_grant = "12345grant"
  721. session_state = "12345state"
  722. access_token = "12345token"
  723. session = client.session
  724. session[SESSION_STATE] = session_state
  725. session.save()
  726. responses.post(
  727. "https://example.com/oauth2/token",
  728. json={
  729. "token": {
  730. "bearer": access_token,
  731. },
  732. },
  733. match=[
  734. urlencoded_params_matcher(
  735. {
  736. "grant_type": "authorization_code",
  737. "client_id": "oauth2_client_id",
  738. "client_secret": "oauth2_client_secret",
  739. "redirect_uri": "http://testserver/oauth2/complete/",
  740. "code": code_grant,
  741. },
  742. ),
  743. ],
  744. )
  745. responses.post(
  746. "https://example.com/oauth2/user",
  747. json={
  748. "id": 1234,
  749. "profile": {
  750. "name": "John Doe",
  751. "email": "john@example.com",
  752. },
  753. },
  754. match=[
  755. header_matcher({"Authorization": f"Bearer {access_token}"}),
  756. ],
  757. )
  758. response = client.get(
  759. "%s?state=%s&code=%s"
  760. % (
  761. reverse("misago:oauth2-complete"),
  762. session_state,
  763. code_grant,
  764. )
  765. )
  766. assert_contains(
  767. response,
  768. (
  769. "User account associated with the profile from the OAuth2 provider "
  770. "was deactivated by the site administrator."
  771. ),
  772. 400,
  773. )
  774. # User is updated but still deactivated
  775. user.refresh_from_db()
  776. assert user.username == "John_Doe"
  777. assert user.slug == "john-doe"
  778. assert user.email == "john@example.com"
  779. assert user.is_active is False
  780. # User is not authenticated
  781. auth_api = client.get(reverse("misago:api:auth")).json()
  782. assert auth_api["id"] is None
  783. # User welcome e-mail is not sent
  784. assert len(mailoutbox) == 0
  785. @responses.activate
  786. @override_dynamic_settings(**TEST_SETTINGS)
  787. def test_oauth2_complete_view_creates_banned_user_but_returns_error_403(
  788. user, client, dynamic_settings, mailoutbox
  789. ):
  790. assert dynamic_settings.enable_oauth2_client is True
  791. user.username = "John_Doe"
  792. ban_user(user, "Banned for a test.")
  793. user.refresh_from_db()
  794. code_grant = "12345grant"
  795. session_state = "12345state"
  796. access_token = "12345token"
  797. session = client.session
  798. session[SESSION_STATE] = session_state
  799. session.save()
  800. responses.post(
  801. "https://example.com/oauth2/token",
  802. json={
  803. "token": {
  804. "bearer": access_token,
  805. },
  806. },
  807. match=[
  808. urlencoded_params_matcher(
  809. {
  810. "grant_type": "authorization_code",
  811. "client_id": "oauth2_client_id",
  812. "client_secret": "oauth2_client_secret",
  813. "redirect_uri": "http://testserver/oauth2/complete/",
  814. "code": code_grant,
  815. },
  816. ),
  817. ],
  818. )
  819. responses.post(
  820. "https://example.com/oauth2/user",
  821. json={
  822. "id": 1234,
  823. "profile": {
  824. "name": "John Doe",
  825. "email": "john@example.com",
  826. },
  827. },
  828. match=[
  829. header_matcher({"Authorization": f"Bearer {access_token}"}),
  830. ],
  831. )
  832. response = client.get(
  833. "%s?state=%s&code=%s"
  834. % (
  835. reverse("misago:oauth2-complete"),
  836. session_state,
  837. code_grant,
  838. )
  839. )
  840. assert_contains(response, "Banned for a test.", 403)
  841. # User is created
  842. new_user = User.objects.get_by_email("john@example.com")
  843. assert new_user
  844. assert new_user.id != user.id
  845. assert new_user.username == "John_Doe"
  846. assert new_user.slug == "john-doe"
  847. assert new_user.email == "john@example.com"
  848. # User is not authenticated
  849. auth_api = client.get(reverse("misago:api:auth")).json()
  850. assert auth_api["id"] is None
  851. # User welcome e-mail is not sent
  852. assert len(mailoutbox) == 0
  853. @responses.activate
  854. @override_dynamic_settings(**TEST_SETTINGS)
  855. def test_oauth2_complete_view_updates_banned_user_but_returns_error_403(
  856. user, client, dynamic_settings, mailoutbox
  857. ):
  858. assert dynamic_settings.enable_oauth2_client is True
  859. Subject.objects.create(sub="1234", user=user)
  860. user.username = "John_Doe"
  861. ban_user(user, "Banned for a test.")
  862. user.refresh_from_db()
  863. code_grant = "12345grant"
  864. session_state = "12345state"
  865. access_token = "12345token"
  866. session = client.session
  867. session[SESSION_STATE] = session_state
  868. session.save()
  869. responses.post(
  870. "https://example.com/oauth2/token",
  871. json={
  872. "token": {
  873. "bearer": access_token,
  874. },
  875. },
  876. match=[
  877. urlencoded_params_matcher(
  878. {
  879. "grant_type": "authorization_code",
  880. "client_id": "oauth2_client_id",
  881. "client_secret": "oauth2_client_secret",
  882. "redirect_uri": "http://testserver/oauth2/complete/",
  883. "code": code_grant,
  884. },
  885. ),
  886. ],
  887. )
  888. responses.post(
  889. "https://example.com/oauth2/user",
  890. json={
  891. "id": 1234,
  892. "profile": {
  893. "name": "John Doe",
  894. "email": "john@example.com",
  895. },
  896. },
  897. match=[
  898. header_matcher({"Authorization": f"Bearer {access_token}"}),
  899. ],
  900. )
  901. response = client.get(
  902. "%s?state=%s&code=%s"
  903. % (
  904. reverse("misago:oauth2-complete"),
  905. session_state,
  906. code_grant,
  907. )
  908. )
  909. assert_contains(response, "Banned for a test.", 403)
  910. # User is updated
  911. user.refresh_from_db()
  912. assert user.username == "John_Doe"
  913. assert user.slug == "john-doe"
  914. assert user.email == "john@example.com"
  915. # User is not authenticated
  916. auth_api = client.get(reverse("misago:api:auth")).json()
  917. assert auth_api["id"] is None
  918. # User welcome e-mail is not sent
  919. assert len(mailoutbox) == 0