test_oauth2_complete_view.py 29 KB

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