Default DB configuration to false and set the default database name to
[akkoma] / test / web / oauth / oauth_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.OAuth.OAuthControllerTest do
6 use Pleroma.Web.ConnCase
7 import Pleroma.Factory
8 import Mock
9
10 alias Pleroma.Registration
11 alias Pleroma.Repo
12 alias Pleroma.Web.OAuth.Authorization
13 alias Pleroma.Web.OAuth.Token
14
15 @oauth_config_path [:oauth2, :issue_new_refresh_token]
16 @session_opts [
17 store: :cookie,
18 key: "_test",
19 signing_salt: "cooldude"
20 ]
21
22 describe "in OAuth consumer mode, " do
23 setup do
24 oauth_consumer_strategies_path = [:auth, :oauth_consumer_strategies]
25 oauth_consumer_strategies = Pleroma.Config.get(oauth_consumer_strategies_path)
26 Pleroma.Config.put(oauth_consumer_strategies_path, ~w(twitter facebook))
27
28 on_exit(fn ->
29 Pleroma.Config.put(oauth_consumer_strategies_path, oauth_consumer_strategies)
30 end)
31
32 [
33 app: insert(:oauth_app),
34 conn:
35 build_conn()
36 |> Plug.Session.call(Plug.Session.init(@session_opts))
37 |> fetch_session()
38 ]
39 end
40
41 test "GET /oauth/authorize renders auth forms, including OAuth consumer form", %{
42 app: app,
43 conn: conn
44 } do
45 conn =
46 get(
47 conn,
48 "/oauth/authorize",
49 %{
50 "response_type" => "code",
51 "client_id" => app.client_id,
52 "redirect_uri" => app.redirect_uris,
53 "scope" => "read"
54 }
55 )
56
57 assert response = html_response(conn, 200)
58 assert response =~ "Sign in with Twitter"
59 assert response =~ o_auth_path(conn, :prepare_request)
60 end
61
62 test "GET /oauth/prepare_request encodes parameters as `state` and redirects", %{
63 app: app,
64 conn: conn
65 } do
66 conn =
67 get(
68 conn,
69 "/oauth/prepare_request",
70 %{
71 "provider" => "twitter",
72 "authorization" => %{
73 "scope" => "read follow",
74 "client_id" => app.client_id,
75 "redirect_uri" => app.redirect_uris,
76 "state" => "a_state"
77 }
78 }
79 )
80
81 assert response = html_response(conn, 302)
82
83 redirect_query = URI.parse(redirected_to(conn)).query
84 assert %{"state" => state_param} = URI.decode_query(redirect_query)
85 assert {:ok, state_components} = Poison.decode(state_param)
86
87 expected_client_id = app.client_id
88 expected_redirect_uri = app.redirect_uris
89
90 assert %{
91 "scope" => "read follow",
92 "client_id" => ^expected_client_id,
93 "redirect_uri" => ^expected_redirect_uri,
94 "state" => "a_state"
95 } = state_components
96 end
97
98 test "with user-bound registration, GET /oauth/<provider>/callback redirects to `redirect_uri` with `code`",
99 %{app: app, conn: conn} do
100 registration = insert(:registration)
101
102 state_params = %{
103 "scope" => Enum.join(app.scopes, " "),
104 "client_id" => app.client_id,
105 "redirect_uri" => app.redirect_uris,
106 "state" => ""
107 }
108
109 with_mock Pleroma.Web.Auth.Authenticator,
110 get_registration: fn _ -> {:ok, registration} end do
111 conn =
112 get(
113 conn,
114 "/oauth/twitter/callback",
115 %{
116 "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
117 "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
118 "provider" => "twitter",
119 "state" => Poison.encode!(state_params)
120 }
121 )
122
123 assert response = html_response(conn, 302)
124 assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
125 end
126 end
127
128 test "with user-unbound registration, GET /oauth/<provider>/callback renders registration_details page",
129 %{app: app, conn: conn} do
130 registration = insert(:registration, user: nil)
131
132 state_params = %{
133 "scope" => "read write",
134 "client_id" => app.client_id,
135 "redirect_uri" => app.redirect_uris,
136 "state" => "a_state"
137 }
138
139 with_mock Pleroma.Web.Auth.Authenticator,
140 get_registration: fn _ -> {:ok, registration} end do
141 conn =
142 get(
143 conn,
144 "/oauth/twitter/callback",
145 %{
146 "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
147 "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
148 "provider" => "twitter",
149 "state" => Poison.encode!(state_params)
150 }
151 )
152
153 assert response = html_response(conn, 200)
154 assert response =~ ~r/name="op" type="submit" value="register"/
155 assert response =~ ~r/name="op" type="submit" value="connect"/
156 assert response =~ Registration.email(registration)
157 assert response =~ Registration.nickname(registration)
158 end
159 end
160
161 test "on authentication error, GET /oauth/<provider>/callback redirects to `redirect_uri`", %{
162 app: app,
163 conn: conn
164 } do
165 state_params = %{
166 "scope" => Enum.join(app.scopes, " "),
167 "client_id" => app.client_id,
168 "redirect_uri" => app.redirect_uris,
169 "state" => ""
170 }
171
172 conn =
173 conn
174 |> assign(:ueberauth_failure, %{errors: [%{message: "(error description)"}]})
175 |> get(
176 "/oauth/twitter/callback",
177 %{
178 "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
179 "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
180 "provider" => "twitter",
181 "state" => Poison.encode!(state_params)
182 }
183 )
184
185 assert response = html_response(conn, 302)
186 assert redirected_to(conn) == app.redirect_uris
187 assert get_flash(conn, :error) == "Failed to authenticate: (error description)."
188 end
189
190 test "GET /oauth/registration_details renders registration details form", %{
191 app: app,
192 conn: conn
193 } do
194 conn =
195 get(
196 conn,
197 "/oauth/registration_details",
198 %{
199 "authorization" => %{
200 "scopes" => app.scopes,
201 "client_id" => app.client_id,
202 "redirect_uri" => app.redirect_uris,
203 "state" => "a_state",
204 "nickname" => nil,
205 "email" => "john@doe.com"
206 }
207 }
208 )
209
210 assert response = html_response(conn, 200)
211 assert response =~ ~r/name="op" type="submit" value="register"/
212 assert response =~ ~r/name="op" type="submit" value="connect"/
213 end
214
215 test "with valid params, POST /oauth/register?op=register redirects to `redirect_uri` with `code`",
216 %{
217 app: app,
218 conn: conn
219 } do
220 registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
221
222 conn =
223 conn
224 |> put_session(:registration_id, registration.id)
225 |> post(
226 "/oauth/register",
227 %{
228 "op" => "register",
229 "authorization" => %{
230 "scopes" => app.scopes,
231 "client_id" => app.client_id,
232 "redirect_uri" => app.redirect_uris,
233 "state" => "a_state",
234 "nickname" => "availablenick",
235 "email" => "available@email.com"
236 }
237 }
238 )
239
240 assert response = html_response(conn, 302)
241 assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
242 end
243
244 test "with invalid params, POST /oauth/register?op=register renders registration_details page",
245 %{
246 app: app,
247 conn: conn
248 } do
249 another_user = insert(:user)
250 registration = insert(:registration, user: nil, info: %{"nickname" => nil, "email" => nil})
251
252 params = %{
253 "op" => "register",
254 "authorization" => %{
255 "scopes" => app.scopes,
256 "client_id" => app.client_id,
257 "redirect_uri" => app.redirect_uris,
258 "state" => "a_state",
259 "nickname" => "availablenickname",
260 "email" => "available@email.com"
261 }
262 }
263
264 for {bad_param, bad_param_value} <-
265 [{"nickname", another_user.nickname}, {"email", another_user.email}] do
266 bad_registration_attrs = %{
267 "authorization" => Map.put(params["authorization"], bad_param, bad_param_value)
268 }
269
270 bad_params = Map.merge(params, bad_registration_attrs)
271
272 conn =
273 conn
274 |> put_session(:registration_id, registration.id)
275 |> post("/oauth/register", bad_params)
276
277 assert html_response(conn, 403) =~ ~r/name="op" type="submit" value="register"/
278 assert get_flash(conn, :error) == "Error: #{bad_param} has already been taken."
279 end
280 end
281
282 test "with valid params, POST /oauth/register?op=connect redirects to `redirect_uri` with `code`",
283 %{
284 app: app,
285 conn: conn
286 } do
287 user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt("testpassword"))
288 registration = insert(:registration, user: nil)
289
290 conn =
291 conn
292 |> put_session(:registration_id, registration.id)
293 |> post(
294 "/oauth/register",
295 %{
296 "op" => "connect",
297 "authorization" => %{
298 "scopes" => app.scopes,
299 "client_id" => app.client_id,
300 "redirect_uri" => app.redirect_uris,
301 "state" => "a_state",
302 "name" => user.nickname,
303 "password" => "testpassword"
304 }
305 }
306 )
307
308 assert response = html_response(conn, 302)
309 assert redirected_to(conn) =~ ~r/#{app.redirect_uris}\?code=.+/
310 end
311
312 test "with invalid params, POST /oauth/register?op=connect renders registration_details page",
313 %{
314 app: app,
315 conn: conn
316 } do
317 user = insert(:user)
318 registration = insert(:registration, user: nil)
319
320 params = %{
321 "op" => "connect",
322 "authorization" => %{
323 "scopes" => app.scopes,
324 "client_id" => app.client_id,
325 "redirect_uri" => app.redirect_uris,
326 "state" => "a_state",
327 "name" => user.nickname,
328 "password" => "wrong password"
329 }
330 }
331
332 conn =
333 conn
334 |> put_session(:registration_id, registration.id)
335 |> post("/oauth/register", params)
336
337 assert html_response(conn, 401) =~ ~r/name="op" type="submit" value="connect"/
338 assert get_flash(conn, :error) == "Invalid Username/Password"
339 end
340 end
341
342 describe "GET /oauth/authorize" do
343 setup do
344 [
345 app: insert(:oauth_app, redirect_uris: "https://redirect.url"),
346 conn:
347 build_conn()
348 |> Plug.Session.call(Plug.Session.init(@session_opts))
349 |> fetch_session()
350 ]
351 end
352
353 test "renders authentication page", %{app: app, conn: conn} do
354 conn =
355 get(
356 conn,
357 "/oauth/authorize",
358 %{
359 "response_type" => "code",
360 "client_id" => app.client_id,
361 "redirect_uri" => app.redirect_uris,
362 "scope" => "read"
363 }
364 )
365
366 assert html_response(conn, 200) =~ ~s(type="submit")
367 end
368
369 test "properly handles internal calls with `authorization`-wrapped params", %{
370 app: app,
371 conn: conn
372 } do
373 conn =
374 get(
375 conn,
376 "/oauth/authorize",
377 %{
378 "authorization" => %{
379 "response_type" => "code",
380 "client_id" => app.client_id,
381 "redirect_uri" => app.redirect_uris,
382 "scope" => "read"
383 }
384 }
385 )
386
387 assert html_response(conn, 200) =~ ~s(type="submit")
388 end
389
390 test "renders authentication page if user is already authenticated but `force_login` is tru-ish",
391 %{app: app, conn: conn} do
392 token = insert(:oauth_token, app_id: app.id)
393
394 conn =
395 conn
396 |> put_session(:oauth_token, token.token)
397 |> get(
398 "/oauth/authorize",
399 %{
400 "response_type" => "code",
401 "client_id" => app.client_id,
402 "redirect_uri" => app.redirect_uris,
403 "scope" => "read",
404 "force_login" => "true"
405 }
406 )
407
408 assert html_response(conn, 200) =~ ~s(type="submit")
409 end
410
411 test "with existing authentication and non-OOB `redirect_uri`, redirects to app with `token` and `state` params",
412 %{
413 app: app,
414 conn: conn
415 } do
416 token = insert(:oauth_token, app_id: app.id)
417
418 conn =
419 conn
420 |> put_session(:oauth_token, token.token)
421 |> get(
422 "/oauth/authorize",
423 %{
424 "response_type" => "code",
425 "client_id" => app.client_id,
426 "redirect_uri" => app.redirect_uris,
427 "state" => "specific_client_state",
428 "scope" => "read"
429 }
430 )
431
432 assert URI.decode(redirected_to(conn)) ==
433 "https://redirect.url?access_token=#{token.token}&state=specific_client_state"
434 end
435
436 test "with existing authentication and OOB `redirect_uri`, redirects to app with `token` and `state` params",
437 %{
438 app: app,
439 conn: conn
440 } do
441 token = insert(:oauth_token, app_id: app.id)
442
443 conn =
444 conn
445 |> put_session(:oauth_token, token.token)
446 |> get(
447 "/oauth/authorize",
448 %{
449 "response_type" => "code",
450 "client_id" => app.client_id,
451 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
452 "scope" => "read"
453 }
454 )
455
456 assert html_response(conn, 200) =~ "Authorization exists"
457 end
458 end
459
460 describe "POST /oauth/authorize" do
461 test "redirects with oauth authorization" do
462 user = insert(:user)
463 app = insert(:oauth_app, scopes: ["read", "write", "follow"])
464
465 conn =
466 build_conn()
467 |> post("/oauth/authorize", %{
468 "authorization" => %{
469 "name" => user.nickname,
470 "password" => "test",
471 "client_id" => app.client_id,
472 "redirect_uri" => app.redirect_uris,
473 "scope" => "read write",
474 "state" => "statepassed"
475 }
476 })
477
478 target = redirected_to(conn)
479 assert target =~ app.redirect_uris
480
481 query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
482
483 assert %{"state" => "statepassed", "code" => code} = query
484 auth = Repo.get_by(Authorization, token: code)
485 assert auth
486 assert auth.scopes == ["read", "write"]
487 end
488
489 test "returns 401 for wrong credentials", %{conn: conn} do
490 user = insert(:user)
491 app = insert(:oauth_app)
492
493 result =
494 conn
495 |> post("/oauth/authorize", %{
496 "authorization" => %{
497 "name" => user.nickname,
498 "password" => "wrong",
499 "client_id" => app.client_id,
500 "redirect_uri" => app.redirect_uris,
501 "state" => "statepassed",
502 "scope" => Enum.join(app.scopes, " ")
503 }
504 })
505 |> html_response(:unauthorized)
506
507 # Keep the details
508 assert result =~ app.client_id
509 assert result =~ app.redirect_uris
510
511 # Error message
512 assert result =~ "Invalid Username/Password"
513 end
514
515 test "returns 401 for missing scopes", %{conn: conn} do
516 user = insert(:user)
517 app = insert(:oauth_app)
518
519 result =
520 conn
521 |> post("/oauth/authorize", %{
522 "authorization" => %{
523 "name" => user.nickname,
524 "password" => "test",
525 "client_id" => app.client_id,
526 "redirect_uri" => app.redirect_uris,
527 "state" => "statepassed",
528 "scope" => ""
529 }
530 })
531 |> html_response(:unauthorized)
532
533 # Keep the details
534 assert result =~ app.client_id
535 assert result =~ app.redirect_uris
536
537 # Error message
538 assert result =~ "This action is outside the authorized scopes"
539 end
540
541 test "returns 401 for scopes beyond app scopes", %{conn: conn} do
542 user = insert(:user)
543 app = insert(:oauth_app, scopes: ["read", "write"])
544
545 result =
546 conn
547 |> post("/oauth/authorize", %{
548 "authorization" => %{
549 "name" => user.nickname,
550 "password" => "test",
551 "client_id" => app.client_id,
552 "redirect_uri" => app.redirect_uris,
553 "state" => "statepassed",
554 "scope" => "read write follow"
555 }
556 })
557 |> html_response(:unauthorized)
558
559 # Keep the details
560 assert result =~ app.client_id
561 assert result =~ app.redirect_uris
562
563 # Error message
564 assert result =~ "This action is outside the authorized scopes"
565 end
566 end
567
568 describe "POST /oauth/token" do
569 test "issues a token for an all-body request" do
570 user = insert(:user)
571 app = insert(:oauth_app, scopes: ["read", "write"])
572
573 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
574
575 conn =
576 build_conn()
577 |> post("/oauth/token", %{
578 "grant_type" => "authorization_code",
579 "code" => auth.token,
580 "redirect_uri" => app.redirect_uris,
581 "client_id" => app.client_id,
582 "client_secret" => app.client_secret
583 })
584
585 assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
586
587 token = Repo.get_by(Token, token: token)
588 assert token
589 assert token.scopes == auth.scopes
590 assert user.ap_id == ap_id
591 end
592
593 test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
594 password = "testpassword"
595 user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
596
597 app = insert(:oauth_app, scopes: ["read", "write"])
598
599 # Note: "scope" param is intentionally omitted
600 conn =
601 build_conn()
602 |> post("/oauth/token", %{
603 "grant_type" => "password",
604 "username" => user.nickname,
605 "password" => password,
606 "client_id" => app.client_id,
607 "client_secret" => app.client_secret
608 })
609
610 assert %{"access_token" => token} = json_response(conn, 200)
611
612 token = Repo.get_by(Token, token: token)
613 assert token
614 assert token.scopes == app.scopes
615 end
616
617 test "issues a token for request with HTTP basic auth client credentials" do
618 user = insert(:user)
619 app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
620
621 {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
622 assert auth.scopes == ["scope1", "scope2"]
623
624 app_encoded =
625 (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
626 |> Base.encode64()
627
628 conn =
629 build_conn()
630 |> put_req_header("authorization", "Basic " <> app_encoded)
631 |> post("/oauth/token", %{
632 "grant_type" => "authorization_code",
633 "code" => auth.token,
634 "redirect_uri" => app.redirect_uris
635 })
636
637 assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
638
639 assert scope == "scope1 scope2"
640
641 token = Repo.get_by(Token, token: token)
642 assert token
643 assert token.scopes == ["scope1", "scope2"]
644 end
645
646 test "issue a token for client_credentials grant type" do
647 app = insert(:oauth_app, scopes: ["read", "write"])
648
649 conn =
650 build_conn()
651 |> post("/oauth/token", %{
652 "grant_type" => "client_credentials",
653 "client_id" => app.client_id,
654 "client_secret" => app.client_secret
655 })
656
657 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
658 json_response(conn, 200)
659
660 assert token
661 token_from_db = Repo.get_by(Token, token: token)
662 assert token_from_db
663 assert refresh
664 assert scope == "read write"
665 end
666
667 test "rejects token exchange with invalid client credentials" do
668 user = insert(:user)
669 app = insert(:oauth_app)
670
671 {:ok, auth} = Authorization.create_authorization(app, user)
672
673 conn =
674 build_conn()
675 |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
676 |> post("/oauth/token", %{
677 "grant_type" => "authorization_code",
678 "code" => auth.token,
679 "redirect_uri" => app.redirect_uris
680 })
681
682 assert resp = json_response(conn, 400)
683 assert %{"error" => _} = resp
684 refute Map.has_key?(resp, "access_token")
685 end
686
687 test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
688 setting = Pleroma.Config.get([:instance, :account_activation_required])
689
690 unless setting do
691 Pleroma.Config.put([:instance, :account_activation_required], true)
692 on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
693 end
694
695 password = "testpassword"
696 user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
697 info_change = Pleroma.User.Info.confirmation_changeset(user.info, need_confirmation: true)
698
699 {:ok, user} =
700 user
701 |> Ecto.Changeset.change()
702 |> Ecto.Changeset.put_embed(:info, info_change)
703 |> Repo.update()
704
705 refute Pleroma.User.auth_active?(user)
706
707 app = insert(:oauth_app)
708
709 conn =
710 build_conn()
711 |> post("/oauth/token", %{
712 "grant_type" => "password",
713 "username" => user.nickname,
714 "password" => password,
715 "client_id" => app.client_id,
716 "client_secret" => app.client_secret
717 })
718
719 assert resp = json_response(conn, 403)
720 assert %{"error" => _} = resp
721 refute Map.has_key?(resp, "access_token")
722 end
723
724 test "rejects token exchange for valid credentials belonging to deactivated user" do
725 password = "testpassword"
726
727 user =
728 insert(:user,
729 password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
730 info: %{deactivated: true}
731 )
732
733 app = insert(:oauth_app)
734
735 conn =
736 build_conn()
737 |> post("/oauth/token", %{
738 "grant_type" => "password",
739 "username" => user.nickname,
740 "password" => password,
741 "client_id" => app.client_id,
742 "client_secret" => app.client_secret
743 })
744
745 assert resp = json_response(conn, 403)
746 assert %{"error" => _} = resp
747 refute Map.has_key?(resp, "access_token")
748 end
749
750 test "rejects an invalid authorization code" do
751 app = insert(:oauth_app)
752
753 conn =
754 build_conn()
755 |> post("/oauth/token", %{
756 "grant_type" => "authorization_code",
757 "code" => "Imobviouslyinvalid",
758 "redirect_uri" => app.redirect_uris,
759 "client_id" => app.client_id,
760 "client_secret" => app.client_secret
761 })
762
763 assert resp = json_response(conn, 400)
764 assert %{"error" => _} = json_response(conn, 400)
765 refute Map.has_key?(resp, "access_token")
766 end
767 end
768
769 describe "POST /oauth/token - refresh token" do
770 setup do
771 oauth_token_config = Pleroma.Config.get(@oauth_config_path)
772
773 on_exit(fn ->
774 Pleroma.Config.get(@oauth_config_path, oauth_token_config)
775 end)
776 end
777
778 test "issues a new access token with keep fresh token" do
779 Pleroma.Config.put(@oauth_config_path, true)
780 user = insert(:user)
781 app = insert(:oauth_app, scopes: ["read", "write"])
782
783 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
784 {:ok, token} = Token.exchange_token(app, auth)
785
786 response =
787 build_conn()
788 |> post("/oauth/token", %{
789 "grant_type" => "refresh_token",
790 "refresh_token" => token.refresh_token,
791 "client_id" => app.client_id,
792 "client_secret" => app.client_secret
793 })
794 |> json_response(200)
795
796 ap_id = user.ap_id
797
798 assert match?(
799 %{
800 "scope" => "write",
801 "token_type" => "Bearer",
802 "expires_in" => 600,
803 "access_token" => _,
804 "refresh_token" => _,
805 "me" => ^ap_id
806 },
807 response
808 )
809
810 refute Repo.get_by(Token, token: token.token)
811 new_token = Repo.get_by(Token, token: response["access_token"])
812 assert new_token.refresh_token == token.refresh_token
813 assert new_token.scopes == auth.scopes
814 assert new_token.user_id == user.id
815 assert new_token.app_id == app.id
816 end
817
818 test "issues a new access token with new fresh token" do
819 Pleroma.Config.put(@oauth_config_path, false)
820 user = insert(:user)
821 app = insert(:oauth_app, scopes: ["read", "write"])
822
823 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
824 {:ok, token} = Token.exchange_token(app, auth)
825
826 response =
827 build_conn()
828 |> post("/oauth/token", %{
829 "grant_type" => "refresh_token",
830 "refresh_token" => token.refresh_token,
831 "client_id" => app.client_id,
832 "client_secret" => app.client_secret
833 })
834 |> json_response(200)
835
836 ap_id = user.ap_id
837
838 assert match?(
839 %{
840 "scope" => "write",
841 "token_type" => "Bearer",
842 "expires_in" => 600,
843 "access_token" => _,
844 "refresh_token" => _,
845 "me" => ^ap_id
846 },
847 response
848 )
849
850 refute Repo.get_by(Token, token: token.token)
851 new_token = Repo.get_by(Token, token: response["access_token"])
852 refute new_token.refresh_token == token.refresh_token
853 assert new_token.scopes == auth.scopes
854 assert new_token.user_id == user.id
855 assert new_token.app_id == app.id
856 end
857
858 test "returns 400 if we try use access token" do
859 user = insert(:user)
860 app = insert(:oauth_app, scopes: ["read", "write"])
861
862 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
863 {:ok, token} = Token.exchange_token(app, auth)
864
865 response =
866 build_conn()
867 |> post("/oauth/token", %{
868 "grant_type" => "refresh_token",
869 "refresh_token" => token.token,
870 "client_id" => app.client_id,
871 "client_secret" => app.client_secret
872 })
873 |> json_response(400)
874
875 assert %{"error" => "Invalid credentials"} == response
876 end
877
878 test "returns 400 if refresh_token invalid" do
879 app = insert(:oauth_app, scopes: ["read", "write"])
880
881 response =
882 build_conn()
883 |> post("/oauth/token", %{
884 "grant_type" => "refresh_token",
885 "refresh_token" => "token.refresh_token",
886 "client_id" => app.client_id,
887 "client_secret" => app.client_secret
888 })
889 |> json_response(400)
890
891 assert %{"error" => "Invalid credentials"} == response
892 end
893
894 test "issues a new token if token expired" do
895 user = insert(:user)
896 app = insert(:oauth_app, scopes: ["read", "write"])
897
898 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
899 {:ok, token} = Token.exchange_token(app, auth)
900
901 change =
902 Ecto.Changeset.change(
903 token,
904 %{valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -86_400 * 30)}
905 )
906
907 {:ok, access_token} = Repo.update(change)
908
909 response =
910 build_conn()
911 |> post("/oauth/token", %{
912 "grant_type" => "refresh_token",
913 "refresh_token" => access_token.refresh_token,
914 "client_id" => app.client_id,
915 "client_secret" => app.client_secret
916 })
917 |> json_response(200)
918
919 ap_id = user.ap_id
920
921 assert match?(
922 %{
923 "scope" => "write",
924 "token_type" => "Bearer",
925 "expires_in" => 600,
926 "access_token" => _,
927 "refresh_token" => _,
928 "me" => ^ap_id
929 },
930 response
931 )
932
933 refute Repo.get_by(Token, token: token.token)
934 token = Repo.get_by(Token, token: response["access_token"])
935 assert token
936 assert token.scopes == auth.scopes
937 assert token.user_id == user.id
938 assert token.app_id == app.id
939 end
940 end
941
942 describe "POST /oauth/token - bad request" do
943 test "returns 500" do
944 response =
945 build_conn()
946 |> post("/oauth/token", %{})
947 |> json_response(500)
948
949 assert %{"error" => "Bad request"} == response
950 end
951 end
952
953 describe "POST /oauth/revoke - bad request" do
954 test "returns 500" do
955 response =
956 build_conn()
957 |> post("/oauth/revoke", %{})
958 |> json_response(500)
959
960 assert %{"error" => "Bad request"} == response
961 end
962 end
963 end