Merge branch '1723-token-fixes' into 'develop'
AccountController: Return scope in proper format. Closes #1723 See merge request pleroma/pleroma!2694
This commit is contained in:
commit
8ca1f3e8c6
|
@ -447,6 +447,7 @@ defp create_request do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: This is actually a token respone, but there's no oauth operation file yet.
|
||||||
defp create_response do
|
defp create_response do
|
||||||
%Schema{
|
%Schema{
|
||||||
title: "AccountCreateResponse",
|
title: "AccountCreateResponse",
|
||||||
|
@ -455,14 +456,20 @@ defp create_response do
|
||||||
properties: %{
|
properties: %{
|
||||||
token_type: %Schema{type: :string},
|
token_type: %Schema{type: :string},
|
||||||
access_token: %Schema{type: :string},
|
access_token: %Schema{type: :string},
|
||||||
scope: %Schema{type: :array, items: %Schema{type: :string}},
|
refresh_token: %Schema{type: :string},
|
||||||
created_at: %Schema{type: :integer, format: :"date-time"}
|
scope: %Schema{type: :string},
|
||||||
|
created_at: %Schema{type: :integer, format: :"date-time"},
|
||||||
|
me: %Schema{type: :string},
|
||||||
|
expires_in: %Schema{type: :integer}
|
||||||
},
|
},
|
||||||
example: %{
|
example: %{
|
||||||
|
"token_type" => "Bearer",
|
||||||
"access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
|
"access_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzk",
|
||||||
|
"refresh_token" => "i9hAVVzGld86Pl5JtLtizKoXVvtTlSCJvwaugCxvZzz",
|
||||||
"created_at" => 1_585_918_714,
|
"created_at" => 1_585_918_714,
|
||||||
"scope" => ["read", "write", "follow", "push"],
|
"expires_in" => 600,
|
||||||
"token_type" => "Bearer"
|
"scope" => "read write follow push",
|
||||||
|
"me" => "https://gensokyo.2hu/users/raymoo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonAPIController
|
alias Pleroma.Web.MastodonAPI.MastodonAPIController
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
alias Pleroma.Web.OAuth.OAuthView
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
|
||||||
|
@ -101,12 +102,7 @@ def create(%{assigns: %{app: app}, body_params: params} = conn, _params) do
|
||||||
:ok <- TwitterAPI.validate_captcha(app, params),
|
:ok <- TwitterAPI.validate_captcha(app, params),
|
||||||
{:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
|
{:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
|
||||||
{:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
|
{:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
|
||||||
json(conn, %{
|
json(conn, OAuthView.render("token.json", %{user: user, token: token}))
|
||||||
token_type: "Bearer",
|
|
||||||
access_token: token.token,
|
|
||||||
scope: app.scopes,
|
|
||||||
created_at: Token.Utils.format_created_at(token)
|
|
||||||
})
|
|
||||||
else
|
else
|
||||||
{:error, error} -> json_response(conn, :bad_request, %{error: error})
|
{:error, error} -> json_response(conn, :bad_request, %{error: error})
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,7 @@ defmodule Pleroma.Web.OAuth.MFAController do
|
||||||
alias Pleroma.Web.Auth.TOTPAuthenticator
|
alias Pleroma.Web.Auth.TOTPAuthenticator
|
||||||
alias Pleroma.Web.OAuth.MFAView, as: View
|
alias Pleroma.Web.OAuth.MFAView, as: View
|
||||||
alias Pleroma.Web.OAuth.OAuthController
|
alias Pleroma.Web.OAuth.OAuthController
|
||||||
|
alias Pleroma.Web.OAuth.OAuthView
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
|
||||||
plug(:fetch_session when action in [:show, :verify])
|
plug(:fetch_session when action in [:show, :verify])
|
||||||
|
@ -74,7 +75,7 @@ def challenge(conn, %{"mfa_token" => mfa_token} = params) do
|
||||||
{:ok, %{user: user, authorization: auth}} <- MFA.Token.validate(mfa_token),
|
{:ok, %{user: user, authorization: auth}} <- MFA.Token.validate(mfa_token),
|
||||||
{:ok, _} <- validates_challenge(user, params),
|
{:ok, _} <- validates_challenge(user, params),
|
||||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||||
json(conn, Token.Response.build(user, token))
|
json(conn, OAuthView.render("token.json", %{user: user, token: token}))
|
||||||
else
|
else
|
||||||
_error ->
|
_error ->
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -5,4 +5,13 @@
|
||||||
defmodule Pleroma.Web.OAuth.MFAView do
|
defmodule Pleroma.Web.OAuth.MFAView do
|
||||||
use Pleroma.Web, :view
|
use Pleroma.Web, :view
|
||||||
import Phoenix.HTML.Form
|
import Phoenix.HTML.Form
|
||||||
|
alias Pleroma.MFA
|
||||||
|
|
||||||
|
def render("mfa_response.json", %{token: token, user: user}) do
|
||||||
|
%{
|
||||||
|
error: "mfa_required",
|
||||||
|
mfa_token: token.token,
|
||||||
|
supported_challenge_types: MFA.supported_methods(user)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
alias Pleroma.Web.OAuth.MFAController
|
alias Pleroma.Web.OAuth.MFAController
|
||||||
|
alias Pleroma.Web.OAuth.MFAView
|
||||||
|
alias Pleroma.Web.OAuth.OAuthView
|
||||||
alias Pleroma.Web.OAuth.Scopes
|
alias Pleroma.Web.OAuth.Scopes
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
|
alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken
|
||||||
|
@ -233,9 +235,7 @@ def token_exchange(
|
||||||
with {:ok, app} <- Token.Utils.fetch_app(conn),
|
with {:ok, app} <- Token.Utils.fetch_app(conn),
|
||||||
{:ok, %{user: user} = token} <- Token.get_by_refresh_token(app, token),
|
{:ok, %{user: user} = token} <- Token.get_by_refresh_token(app, token),
|
||||||
{:ok, token} <- RefreshToken.grant(token) do
|
{:ok, token} <- RefreshToken.grant(token) do
|
||||||
response_attrs = %{created_at: Token.Utils.format_created_at(token)}
|
json(conn, OAuthView.render("token.json", %{user: user, token: token}))
|
||||||
|
|
||||||
json(conn, Token.Response.build(user, token, response_attrs))
|
|
||||||
else
|
else
|
||||||
_error -> render_invalid_credentials_error(conn)
|
_error -> render_invalid_credentials_error(conn)
|
||||||
end
|
end
|
||||||
|
@ -247,9 +247,7 @@ def token_exchange(%Plug.Conn{} = conn, %{"grant_type" => "authorization_code"}
|
||||||
{:ok, auth} <- Authorization.get_by_token(app, fixed_token),
|
{:ok, auth} <- Authorization.get_by_token(app, fixed_token),
|
||||||
%User{} = user <- User.get_cached_by_id(auth.user_id),
|
%User{} = user <- User.get_cached_by_id(auth.user_id),
|
||||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||||
response_attrs = %{created_at: Token.Utils.format_created_at(token)}
|
json(conn, OAuthView.render("token.json", %{user: user, token: token}))
|
||||||
|
|
||||||
json(conn, Token.Response.build(user, token, response_attrs))
|
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
handle_token_exchange_error(conn, error)
|
handle_token_exchange_error(conn, error)
|
||||||
|
@ -267,7 +265,7 @@ def token_exchange(
|
||||||
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
|
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
|
||||||
{:mfa_required, _, _, false} <- {:mfa_required, user, auth, MFA.require?(user)},
|
{:mfa_required, _, _, false} <- {:mfa_required, user, auth, MFA.require?(user)},
|
||||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||||
json(conn, Token.Response.build(user, token))
|
json(conn, OAuthView.render("token.json", %{user: user, token: token}))
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
handle_token_exchange_error(conn, error)
|
handle_token_exchange_error(conn, error)
|
||||||
|
@ -290,7 +288,7 @@ def token_exchange(%Plug.Conn{} = conn, %{"grant_type" => "client_credentials"}
|
||||||
with {:ok, app} <- Token.Utils.fetch_app(conn),
|
with {:ok, app} <- Token.Utils.fetch_app(conn),
|
||||||
{:ok, auth} <- Authorization.create_authorization(app, %User{}),
|
{:ok, auth} <- Authorization.create_authorization(app, %User{}),
|
||||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||||
json(conn, Token.Response.build_for_client_credentials(token))
|
json(conn, OAuthView.render("token.json", %{token: token}))
|
||||||
else
|
else
|
||||||
_error ->
|
_error ->
|
||||||
handle_token_exchange_error(conn, :invalid_credentails)
|
handle_token_exchange_error(conn, :invalid_credentails)
|
||||||
|
@ -548,7 +546,7 @@ defp put_session_registration_id(%Plug.Conn{} = conn, registration_id),
|
||||||
|
|
||||||
defp build_and_response_mfa_token(user, auth) do
|
defp build_and_response_mfa_token(user, auth) do
|
||||||
with {:ok, token} <- MFA.Token.create_token(user, auth) do
|
with {:ok, token} <- MFA.Token.create_token(user, auth) do
|
||||||
Token.Response.build_for_mfa_token(user, token)
|
MFAView.render("mfa_response.json", %{token: token, user: user})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,26 @@
|
||||||
defmodule Pleroma.Web.OAuth.OAuthView do
|
defmodule Pleroma.Web.OAuth.OAuthView do
|
||||||
use Pleroma.Web, :view
|
use Pleroma.Web, :view
|
||||||
import Phoenix.HTML.Form
|
import Phoenix.HTML.Form
|
||||||
|
|
||||||
|
alias Pleroma.Web.OAuth.Token.Utils
|
||||||
|
|
||||||
|
def render("token.json", %{token: token} = opts) do
|
||||||
|
response = %{
|
||||||
|
token_type: "Bearer",
|
||||||
|
access_token: token.token,
|
||||||
|
refresh_token: token.refresh_token,
|
||||||
|
expires_in: expires_in(),
|
||||||
|
scope: Enum.join(token.scopes, " "),
|
||||||
|
created_at: Utils.format_created_at(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user = opts[:user] do
|
||||||
|
response
|
||||||
|
|> Map.put(:me, user.ap_id)
|
||||||
|
else
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp expires_in, do: Pleroma.Config.get([:oauth2, :token_expires_in], 600)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.OAuth.Token.Response do
|
|
||||||
@moduledoc false
|
|
||||||
|
|
||||||
alias Pleroma.MFA
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Web.OAuth.Token.Utils
|
|
||||||
|
|
||||||
@doc false
|
|
||||||
def build(%User{} = user, token, opts \\ %{}) do
|
|
||||||
%{
|
|
||||||
token_type: "Bearer",
|
|
||||||
access_token: token.token,
|
|
||||||
refresh_token: token.refresh_token,
|
|
||||||
expires_in: expires_in(),
|
|
||||||
scope: Enum.join(token.scopes, " "),
|
|
||||||
me: user.ap_id
|
|
||||||
}
|
|
||||||
|> Map.merge(opts)
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_for_client_credentials(token) do
|
|
||||||
%{
|
|
||||||
token_type: "Bearer",
|
|
||||||
access_token: token.token,
|
|
||||||
refresh_token: token.refresh_token,
|
|
||||||
created_at: Utils.format_created_at(token),
|
|
||||||
expires_in: expires_in(),
|
|
||||||
scope: Enum.join(token.scopes, " ")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def build_for_mfa_token(user, mfa_token) do
|
|
||||||
%{
|
|
||||||
error: "mfa_required",
|
|
||||||
mfa_token: mfa_token.token,
|
|
||||||
supported_challenge_types: MFA.supported_methods(user)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
defp expires_in, do: Pleroma.Config.get([:oauth2, :token_expires_in], 600)
|
|
||||||
end
|
|
|
@ -937,7 +937,7 @@ test "Account registration via Application", %{conn: conn} do
|
||||||
%{
|
%{
|
||||||
"access_token" => token,
|
"access_token" => token,
|
||||||
"created_at" => _created_at,
|
"created_at" => _created_at,
|
||||||
"scope" => _scope,
|
"scope" => ^scope,
|
||||||
"token_type" => "Bearer"
|
"token_type" => "Bearer"
|
||||||
} = json_response_and_validate_schema(conn, 200)
|
} = json_response_and_validate_schema(conn, 200)
|
||||||
|
|
||||||
|
@ -1099,7 +1099,7 @@ test "registration from trusted app" do
|
||||||
assert %{
|
assert %{
|
||||||
"access_token" => access_token,
|
"access_token" => access_token,
|
||||||
"created_at" => _,
|
"created_at" => _,
|
||||||
"scope" => ["read", "write", "follow", "push"],
|
"scope" => "read write follow push",
|
||||||
"token_type" => "Bearer"
|
"token_type" => "Bearer"
|
||||||
} = response
|
} = response
|
||||||
|
|
||||||
|
@ -1217,7 +1217,7 @@ test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
|
||||||
assert %{
|
assert %{
|
||||||
"access_token" => access_token,
|
"access_token" => access_token,
|
||||||
"created_at" => _,
|
"created_at" => _,
|
||||||
"scope" => ["read"],
|
"scope" => "read",
|
||||||
"token_type" => "Bearer"
|
"token_type" => "Bearer"
|
||||||
} =
|
} =
|
||||||
conn
|
conn
|
||||||
|
|
Loading…
Reference in a new issue