ability to set and reset avatar, profile banner and backgroud in Mastodon API
[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 "redirects to app if user is already authenticated", %{app: app, conn: conn} do
412 token = insert(:oauth_token, app_id: app.id)
413
414 conn =
415 conn
416 |> put_session(:oauth_token, token.token)
417 |> get(
418 "/oauth/authorize",
419 %{
420 "response_type" => "code",
421 "client_id" => app.client_id,
422 "redirect_uri" => app.redirect_uris,
423 "scope" => "read"
424 }
425 )
426
427 assert redirected_to(conn) == "https://redirect.url"
428 end
429 end
430
431 describe "POST /oauth/authorize" do
432 test "redirects with oauth authorization" do
433 user = insert(:user)
434 app = insert(:oauth_app, scopes: ["read", "write", "follow"])
435
436 conn =
437 build_conn()
438 |> post("/oauth/authorize", %{
439 "authorization" => %{
440 "name" => user.nickname,
441 "password" => "test",
442 "client_id" => app.client_id,
443 "redirect_uri" => app.redirect_uris,
444 "scope" => "read write",
445 "state" => "statepassed"
446 }
447 })
448
449 target = redirected_to(conn)
450 assert target =~ app.redirect_uris
451
452 query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
453
454 assert %{"state" => "statepassed", "code" => code} = query
455 auth = Repo.get_by(Authorization, token: code)
456 assert auth
457 assert auth.scopes == ["read", "write"]
458 end
459
460 test "returns 401 for wrong credentials", %{conn: conn} do
461 user = insert(:user)
462 app = insert(:oauth_app)
463
464 result =
465 conn
466 |> post("/oauth/authorize", %{
467 "authorization" => %{
468 "name" => user.nickname,
469 "password" => "wrong",
470 "client_id" => app.client_id,
471 "redirect_uri" => app.redirect_uris,
472 "state" => "statepassed",
473 "scope" => Enum.join(app.scopes, " ")
474 }
475 })
476 |> html_response(:unauthorized)
477
478 # Keep the details
479 assert result =~ app.client_id
480 assert result =~ app.redirect_uris
481
482 # Error message
483 assert result =~ "Invalid Username/Password"
484 end
485
486 test "returns 401 for missing scopes", %{conn: conn} do
487 user = insert(:user)
488 app = insert(:oauth_app)
489
490 result =
491 conn
492 |> post("/oauth/authorize", %{
493 "authorization" => %{
494 "name" => user.nickname,
495 "password" => "test",
496 "client_id" => app.client_id,
497 "redirect_uri" => app.redirect_uris,
498 "state" => "statepassed",
499 "scope" => ""
500 }
501 })
502 |> html_response(:unauthorized)
503
504 # Keep the details
505 assert result =~ app.client_id
506 assert result =~ app.redirect_uris
507
508 # Error message
509 assert result =~ "This action is outside the authorized scopes"
510 end
511
512 test "returns 401 for scopes beyond app scopes", %{conn: conn} do
513 user = insert(:user)
514 app = insert(:oauth_app, scopes: ["read", "write"])
515
516 result =
517 conn
518 |> post("/oauth/authorize", %{
519 "authorization" => %{
520 "name" => user.nickname,
521 "password" => "test",
522 "client_id" => app.client_id,
523 "redirect_uri" => app.redirect_uris,
524 "state" => "statepassed",
525 "scope" => "read write follow"
526 }
527 })
528 |> html_response(:unauthorized)
529
530 # Keep the details
531 assert result =~ app.client_id
532 assert result =~ app.redirect_uris
533
534 # Error message
535 assert result =~ "This action is outside the authorized scopes"
536 end
537 end
538
539 describe "POST /oauth/token" do
540 test "issues a token for an all-body request" do
541 user = insert(:user)
542 app = insert(:oauth_app, scopes: ["read", "write"])
543
544 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
545
546 conn =
547 build_conn()
548 |> post("/oauth/token", %{
549 "grant_type" => "authorization_code",
550 "code" => auth.token,
551 "redirect_uri" => app.redirect_uris,
552 "client_id" => app.client_id,
553 "client_secret" => app.client_secret
554 })
555
556 assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
557
558 token = Repo.get_by(Token, token: token)
559 assert token
560 assert token.scopes == auth.scopes
561 assert user.ap_id == ap_id
562 end
563
564 test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
565 password = "testpassword"
566 user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
567
568 app = insert(:oauth_app, scopes: ["read", "write"])
569
570 # Note: "scope" param is intentionally omitted
571 conn =
572 build_conn()
573 |> post("/oauth/token", %{
574 "grant_type" => "password",
575 "username" => user.nickname,
576 "password" => password,
577 "client_id" => app.client_id,
578 "client_secret" => app.client_secret
579 })
580
581 assert %{"access_token" => token} = json_response(conn, 200)
582
583 token = Repo.get_by(Token, token: token)
584 assert token
585 assert token.scopes == app.scopes
586 end
587
588 test "issues a token for request with HTTP basic auth client credentials" do
589 user = insert(:user)
590 app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
591
592 {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
593 assert auth.scopes == ["scope1", "scope2"]
594
595 app_encoded =
596 (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
597 |> Base.encode64()
598
599 conn =
600 build_conn()
601 |> put_req_header("authorization", "Basic " <> app_encoded)
602 |> post("/oauth/token", %{
603 "grant_type" => "authorization_code",
604 "code" => auth.token,
605 "redirect_uri" => app.redirect_uris
606 })
607
608 assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
609
610 assert scope == "scope1 scope2"
611
612 token = Repo.get_by(Token, token: token)
613 assert token
614 assert token.scopes == ["scope1", "scope2"]
615 end
616
617 test "issue a token for client_credentials grant type" do
618 app = insert(:oauth_app, scopes: ["read", "write"])
619
620 conn =
621 build_conn()
622 |> post("/oauth/token", %{
623 "grant_type" => "client_credentials",
624 "client_id" => app.client_id,
625 "client_secret" => app.client_secret
626 })
627
628 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
629 json_response(conn, 200)
630
631 assert token
632 token_from_db = Repo.get_by(Token, token: token)
633 assert token_from_db
634 assert refresh
635 assert scope == "read write"
636 end
637
638 test "rejects token exchange with invalid client credentials" do
639 user = insert(:user)
640 app = insert(:oauth_app)
641
642 {:ok, auth} = Authorization.create_authorization(app, user)
643
644 conn =
645 build_conn()
646 |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
647 |> post("/oauth/token", %{
648 "grant_type" => "authorization_code",
649 "code" => auth.token,
650 "redirect_uri" => app.redirect_uris
651 })
652
653 assert resp = json_response(conn, 400)
654 assert %{"error" => _} = resp
655 refute Map.has_key?(resp, "access_token")
656 end
657
658 test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
659 setting = Pleroma.Config.get([:instance, :account_activation_required])
660
661 unless setting do
662 Pleroma.Config.put([:instance, :account_activation_required], true)
663 on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
664 end
665
666 password = "testpassword"
667 user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
668 info_change = Pleroma.User.Info.confirmation_changeset(user.info, need_confirmation: true)
669
670 {:ok, user} =
671 user
672 |> Ecto.Changeset.change()
673 |> Ecto.Changeset.put_embed(:info, info_change)
674 |> Repo.update()
675
676 refute Pleroma.User.auth_active?(user)
677
678 app = insert(:oauth_app)
679
680 conn =
681 build_conn()
682 |> post("/oauth/token", %{
683 "grant_type" => "password",
684 "username" => user.nickname,
685 "password" => password,
686 "client_id" => app.client_id,
687 "client_secret" => app.client_secret
688 })
689
690 assert resp = json_response(conn, 403)
691 assert %{"error" => _} = resp
692 refute Map.has_key?(resp, "access_token")
693 end
694
695 test "rejects token exchange for valid credentials belonging to deactivated user" do
696 password = "testpassword"
697
698 user =
699 insert(:user,
700 password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
701 info: %{deactivated: true}
702 )
703
704 app = insert(:oauth_app)
705
706 conn =
707 build_conn()
708 |> post("/oauth/token", %{
709 "grant_type" => "password",
710 "username" => user.nickname,
711 "password" => password,
712 "client_id" => app.client_id,
713 "client_secret" => app.client_secret
714 })
715
716 assert resp = json_response(conn, 403)
717 assert %{"error" => _} = resp
718 refute Map.has_key?(resp, "access_token")
719 end
720
721 test "rejects an invalid authorization code" do
722 app = insert(:oauth_app)
723
724 conn =
725 build_conn()
726 |> post("/oauth/token", %{
727 "grant_type" => "authorization_code",
728 "code" => "Imobviouslyinvalid",
729 "redirect_uri" => app.redirect_uris,
730 "client_id" => app.client_id,
731 "client_secret" => app.client_secret
732 })
733
734 assert resp = json_response(conn, 400)
735 assert %{"error" => _} = json_response(conn, 400)
736 refute Map.has_key?(resp, "access_token")
737 end
738 end
739
740 describe "POST /oauth/token - refresh token" do
741 setup do
742 oauth_token_config = Pleroma.Config.get(@oauth_config_path)
743
744 on_exit(fn ->
745 Pleroma.Config.get(@oauth_config_path, oauth_token_config)
746 end)
747 end
748
749 test "issues a new access token with keep fresh token" do
750 Pleroma.Config.put(@oauth_config_path, true)
751 user = insert(:user)
752 app = insert(:oauth_app, scopes: ["read", "write"])
753
754 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
755 {:ok, token} = Token.exchange_token(app, auth)
756
757 response =
758 build_conn()
759 |> post("/oauth/token", %{
760 "grant_type" => "refresh_token",
761 "refresh_token" => token.refresh_token,
762 "client_id" => app.client_id,
763 "client_secret" => app.client_secret
764 })
765 |> json_response(200)
766
767 ap_id = user.ap_id
768
769 assert match?(
770 %{
771 "scope" => "write",
772 "token_type" => "Bearer",
773 "expires_in" => 600,
774 "access_token" => _,
775 "refresh_token" => _,
776 "me" => ^ap_id
777 },
778 response
779 )
780
781 refute Repo.get_by(Token, token: token.token)
782 new_token = Repo.get_by(Token, token: response["access_token"])
783 assert new_token.refresh_token == token.refresh_token
784 assert new_token.scopes == auth.scopes
785 assert new_token.user_id == user.id
786 assert new_token.app_id == app.id
787 end
788
789 test "issues a new access token with new fresh token" do
790 Pleroma.Config.put(@oauth_config_path, false)
791 user = insert(:user)
792 app = insert(:oauth_app, scopes: ["read", "write"])
793
794 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
795 {:ok, token} = Token.exchange_token(app, auth)
796
797 response =
798 build_conn()
799 |> post("/oauth/token", %{
800 "grant_type" => "refresh_token",
801 "refresh_token" => token.refresh_token,
802 "client_id" => app.client_id,
803 "client_secret" => app.client_secret
804 })
805 |> json_response(200)
806
807 ap_id = user.ap_id
808
809 assert match?(
810 %{
811 "scope" => "write",
812 "token_type" => "Bearer",
813 "expires_in" => 600,
814 "access_token" => _,
815 "refresh_token" => _,
816 "me" => ^ap_id
817 },
818 response
819 )
820
821 refute Repo.get_by(Token, token: token.token)
822 new_token = Repo.get_by(Token, token: response["access_token"])
823 refute new_token.refresh_token == token.refresh_token
824 assert new_token.scopes == auth.scopes
825 assert new_token.user_id == user.id
826 assert new_token.app_id == app.id
827 end
828
829 test "returns 400 if we try use access token" do
830 user = insert(:user)
831 app = insert(:oauth_app, scopes: ["read", "write"])
832
833 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
834 {:ok, token} = Token.exchange_token(app, auth)
835
836 response =
837 build_conn()
838 |> post("/oauth/token", %{
839 "grant_type" => "refresh_token",
840 "refresh_token" => token.token,
841 "client_id" => app.client_id,
842 "client_secret" => app.client_secret
843 })
844 |> json_response(400)
845
846 assert %{"error" => "Invalid credentials"} == response
847 end
848
849 test "returns 400 if refresh_token invalid" do
850 app = insert(:oauth_app, scopes: ["read", "write"])
851
852 response =
853 build_conn()
854 |> post("/oauth/token", %{
855 "grant_type" => "refresh_token",
856 "refresh_token" => "token.refresh_token",
857 "client_id" => app.client_id,
858 "client_secret" => app.client_secret
859 })
860 |> json_response(400)
861
862 assert %{"error" => "Invalid credentials"} == response
863 end
864
865 test "issues a new token if token expired" do
866 user = insert(:user)
867 app = insert(:oauth_app, scopes: ["read", "write"])
868
869 {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
870 {:ok, token} = Token.exchange_token(app, auth)
871
872 change =
873 Ecto.Changeset.change(
874 token,
875 %{valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -86_400 * 30)}
876 )
877
878 {:ok, access_token} = Repo.update(change)
879
880 response =
881 build_conn()
882 |> post("/oauth/token", %{
883 "grant_type" => "refresh_token",
884 "refresh_token" => access_token.refresh_token,
885 "client_id" => app.client_id,
886 "client_secret" => app.client_secret
887 })
888 |> json_response(200)
889
890 ap_id = user.ap_id
891
892 assert match?(
893 %{
894 "scope" => "write",
895 "token_type" => "Bearer",
896 "expires_in" => 600,
897 "access_token" => _,
898 "refresh_token" => _,
899 "me" => ^ap_id
900 },
901 response
902 )
903
904 refute Repo.get_by(Token, token: token.token)
905 token = Repo.get_by(Token, token: response["access_token"])
906 assert token
907 assert token.scopes == auth.scopes
908 assert token.user_id == user.id
909 assert token.app_id == app.id
910 end
911 end
912
913 describe "POST /oauth/token - bad request" do
914 test "returns 500" do
915 response =
916 build_conn()
917 |> post("/oauth/token", %{})
918 |> json_response(500)
919
920 assert %{"error" => "Bad request"} == response
921 end
922 end
923
924 describe "POST /oauth/revoke - bad request" do
925 test "returns 500" do
926 response =
927 build_conn()
928 |> post("/oauth/revoke", %{})
929 |> json_response(500)
930
931 assert %{"error" => "Bad request"} == response
932 end
933 end
934 end