From bb0ec90a135c28b58cf566f0fe8d1efc1c0bdade Mon Sep 17 00:00:00 2001 From: Filip Vavera Date: Tue, 19 Dec 2023 23:35:41 +0100 Subject: [PATCH] style: correctly format all files Signed-off-by: Filip Vavera --- .formatter.exs | 2 +- CHANGELOG.md | 2 +- config/config.exs | 28 +- config/test.exs | 23 -- lib/ex_oauth2_provider.ex | 14 +- .../access_grants/access_grant.ex | 10 +- .../access_grants/access_grants.ex | 3 +- .../access_tokens/access_token.ex | 4 +- .../access_tokens/access_tokens.ex | 54 ++- .../applications/application.ex | 24 +- .../applications/applications.ex | 16 +- lib/ex_oauth2_provider/mixin/expirable.ex | 5 +- lib/ex_oauth2_provider/mixin/revocable.ex | 3 +- lib/ex_oauth2_provider/mixin/scopes.ex | 27 +- .../oauth2/authorization.ex | 51 ++- .../oauth2/authorization/strategy/code.ex | 54 ++- .../oauth2/authorization/utils.ex | 16 +- .../oauth2/authorization/utils/response.ex | 47 ++- lib/ex_oauth2_provider/oauth2/token.ex | 14 +- .../token/strategy/authorization_code.ex | 56 +++- .../token/strategy/client_credentials.ex | 17 +- .../oauth2/token/strategy/password.ex | 49 ++- .../oauth2/token/strategy/refresh_token.ex | 50 ++- .../oauth2/token/strategy/revoke.ex | 40 ++- lib/ex_oauth2_provider/oauth2/token/utils.ex | 7 +- .../oauth2/token/utils/response.ex | 45 ++- lib/ex_oauth2_provider/oauth2/utils/error.ex | 17 +- lib/ex_oauth2_provider/plug.ex | 3 +- .../plug/ensure_authenticated.ex | 1 + lib/ex_oauth2_provider/plug/ensure_scopes.ex | 5 +- lib/ex_oauth2_provider/plug/error_handler.ex | 22 +- lib/ex_oauth2_provider/plug/verify_header.ex | 9 +- lib/ex_oauth2_provider/redirect_uri.ex | 3 +- lib/ex_oauth2_provider/schema.ex | 2 +- lib/mix/ex_oauth2_provider/config.ex | 3 +- lib/mix/ex_oauth2_provider/migration.ex | 50 ++- lib/mix/ex_oauth2_provider/schema.ex | 44 ++- lib/mix/tasks/ex_oauth2_provider.ex | 6 +- .../tasks/ex_oauth2_provider.gen.migration.ex | 8 +- .../tasks/ex_oauth2_provider.gen.schemas.ex | 6 +- lib/mix/tasks/ex_oauth2_provider.install.ex | 21 +- mix.exs | 24 +- mix.lock | 35 +- .../access_grants/access_grants_test.exs | 55 +++- .../access_tokens/access_tokens_test.exs | 310 ++++++++++++++---- .../applications/application_test.exs | 12 +- .../applications/applications_test.exs | 152 +++++++-- .../authorization/strategy/code_test.exs | 195 +++++++---- .../oauth2/authorization_test.exs | 96 ++++-- .../strategy/authorization_code_test.exs | 101 ++++-- .../strategy/client_credentials_test.exs | 32 +- .../oauth2/token/strategy/password_test.exs | 102 ++++-- .../token/strategy/refresh_token_test.exs | 110 +++++-- .../oauth2/token/strategy/revoke_test.exs | 50 ++- test/ex_oauth2_provider/oauth2/token_test.exs | 28 +- .../plug/ensure_scopes_test.exs | 2 +- .../plug/error_handler_test.exs | 4 +- .../plug/verify_header_test.exs | 15 +- test/ex_oauth2_provider_test.exs | 63 +++- .../ex_oauth2_provider.gen.migration_test.exs | 30 +- .../ex_oauth2_provider.gen.schemas_test.exs | 20 +- .../tasks/ex_oauth2_provider.install_test.exs | 10 +- test/support/auth.ex | 6 +- test/support/fixtures.ex | 31 +- test/support/lib/dummy/user.ex | 4 +- test/support/mix/test_case.ex | 4 +- .../support/priv/migrations/1_create_user.exs | 5 +- .../priv/migrations/2_create_oauth_tables.exs | 6 +- test/test_helper.exs | 2 - 69 files changed, 1673 insertions(+), 692 deletions(-) delete mode 100644 config/test.exs diff --git a/.formatter.exs b/.formatter.exs index da03d404..3bfff237 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,3 +1,3 @@ [ - inputs: ["mix.exs", "config/*.exs", "lib/*/**.ex", "test/*/**.exs"] + inputs: ["mix.exs", ".*.exs", "{lib,test,config}/**/*.{ex,exs}"] ] diff --git a/CHANGELOG.md b/CHANGELOG.md index b0d6adef..e99a594d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,4 +63,4 @@ Config now has the form `config :my_app, ExOauth2Provider`. You can still use th If your configuration has `:resource_owner` setting with a UUID, you should remove it and only use the module name for your user schema. UUID is now handled in the schema modules directly. -The schemas can be generated with `mix ex_oauth2_provider.install --no-migrations --binary-id`. \ No newline at end of file +The schemas can be generated with `mix ex_oauth2_provider.install --no-migrations --binary-id`. diff --git a/config/config.exs b/config/config.exs index c4f4b17b..90e5c3dd 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,5 +1,29 @@ import Config -if Mix.env() == :test do - import_config "test.exs" +# configuration is only used for tests +if config_env() == :test do + # Print only warnings and errors during test + config :logger, level: :warning + + config :ex_oauth2_provider, namespace: Dummy + + config :ex_oauth2_provider, ExOauth2Provider, + repo: Dummy.Repo, + resource_owner: Dummy.Users.User, + default_scopes: ~w(public), + optional_scopes: ~w(read write), + password_auth: {Dummy.Auth, :auth}, + use_refresh_token: true, + revoke_refresh_token_on_use: true, + grant_flows: ~w(authorization_code client_credentials) + + config :ex_oauth2_provider, Dummy.Repo, + database: System.get_env("POSTGRES_DATABASE") || "ex_oauth2_provider_test", + username: System.get_env("POSTGRES_USERNAME") || "postgres", + password: System.get_env("POSTGRES_PASSWORD") || "postgres", + hostname: System.get_env("POSTGRES_HOSTNAME") || "localhost", + port: (System.get_env("POSTGRES_PORT") || "5432") |> String.to_integer(), + pool: Ecto.Adapters.SQL.Sandbox, + priv: "test/support/priv", + url: System.get_env("POSTGRES_URL") end diff --git a/config/test.exs b/config/test.exs deleted file mode 100644 index bd80a8e5..00000000 --- a/config/test.exs +++ /dev/null @@ -1,23 +0,0 @@ -import Config - -config :ex_oauth2_provider, namespace: Dummy - -config :ex_oauth2_provider, ExOauth2Provider, - repo: Dummy.Repo, - resource_owner: Dummy.Users.User, - default_scopes: ~w(public), - optional_scopes: ~w(read write), - password_auth: {Dummy.Auth, :auth}, - use_refresh_token: true, - revoke_refresh_token_on_use: true, - grant_flows: ~w(authorization_code client_credentials) - -config :ex_oauth2_provider, Dummy.Repo, - database: System.get_env("POSTGRES_DATABASE") || "ex_oauth2_provider_test", - username: System.get_env("POSTGRES_USERNAME") || "postgres", - password: System.get_env("POSTGRES_PASSWORD") || "postgres", - hostname: System.get_env("POSTGRES_HOSTNAME") || "localhost", - port: (System.get_env("POSTGRES_PORT") || "5432") |> String.to_integer(), - pool: Ecto.Adapters.SQL.Sandbox, - priv: "test/support/priv", - url: System.get_env("POSTGRES_URL") diff --git a/lib/ex_oauth2_provider.ex b/lib/ex_oauth2_provider.ex index 8d4f40b1..ec1edc72 100644 --- a/lib/ex_oauth2_provider.ex +++ b/lib/ex_oauth2_provider.ex @@ -51,6 +51,7 @@ defmodule ExOauth2Provider do @spec authenticate_token(binary(), keyword()) :: {:ok, map()} | {:error, any()} def authenticate_token(token, config \\ []) def authenticate_token(nil, _config), do: {:error, :token_inaccessible} + def authenticate_token(token, config) do token |> load_access_token(config) @@ -61,37 +62,40 @@ defmodule ExOauth2Provider do defp load_access_token(token, config) do case AccessTokens.get_by_token(token, config) do - nil -> {:error, :token_not_found} + nil -> {:error, :token_not_found} access_token -> {:ok, access_token} end end defp maybe_revoke_previous_refresh_token({:error, error}, _config), do: {:error, error} + defp maybe_revoke_previous_refresh_token({:ok, access_token}, config) do case Config.refresh_token_revoked_on_use?(config) do - true -> revoke_previous_refresh_token(access_token, config) + true -> revoke_previous_refresh_token(access_token, config) false -> {:ok, access_token} end end defp revoke_previous_refresh_token(access_token, config) do case AccessTokens.revoke_previous_refresh_token(access_token, config) do - {:error, _any} -> {:error, :no_association_found} + {:error, _any} -> {:error, :no_association_found} {:ok, _access_token} -> {:ok, access_token} end end defp validate_access_token({:error, error}), do: {:error, error} + defp validate_access_token({:ok, access_token}) do case AccessTokens.is_accessible?(access_token) do - true -> {:ok, access_token} + true -> {:ok, access_token} false -> {:error, :token_inaccessible} end end defp load_resource_owner({:error, error}, _config), do: {:error, error} + defp load_resource_owner({:ok, access_token}, config) do - repo = Config.repo(config) + repo = Config.repo(config) access_token = repo.preload(access_token, :resource_owner) {:ok, access_token} diff --git a/lib/ex_oauth2_provider/access_grants/access_grant.ex b/lib/ex_oauth2_provider/access_grants/access_grant.ex index d3071bbf..cb6cbfb4 100644 --- a/lib/ex_oauth2_provider/access_grants/access_grant.ex +++ b/lib/ex_oauth2_provider/access_grants/access_grant.ex @@ -42,7 +42,7 @@ defmodule ExOauth2Provider.AccessGrants.AccessGrant do @doc false def indexes() do [ - {:token, true}, + {:token, true} ] end @@ -72,7 +72,13 @@ defmodule ExOauth2Provider.AccessGrants.AccessGrant do |> put_token() |> Scopes.put_scopes(grant.application.scopes, config) |> Scopes.validate_scopes(grant.application.scopes, config) - |> Changeset.validate_required([:redirect_uri, :expires_in, :token, :resource_owner, :application]) + |> Changeset.validate_required([ + :redirect_uri, + :expires_in, + :token, + :resource_owner, + :application + ]) |> Changeset.unique_constraint(:token) end diff --git a/lib/ex_oauth2_provider/access_grants/access_grants.ex b/lib/ex_oauth2_provider/access_grants/access_grants.ex index 9eab4bb5..bbecff5d 100644 --- a/lib/ex_oauth2_provider/access_grants/access_grants.ex +++ b/lib/ex_oauth2_provider/access_grants/access_grants.ex @@ -42,7 +42,8 @@ defmodule ExOauth2Provider.AccessGrants do {:error, %Ecto.Changeset{}} """ - @spec create_grant(Ecto.Schema.t(), Application.t(), map(), keyword()) :: {:ok, AccessGrant.t()} | {:error, term()} + @spec create_grant(Ecto.Schema.t(), Application.t(), map(), keyword()) :: + {:ok, AccessGrant.t()} | {:error, term()} def create_grant(resource_owner, application, attrs, config \\ []) do config |> Config.access_grant() diff --git a/lib/ex_oauth2_provider/access_tokens/access_token.ex b/lib/ex_oauth2_provider/access_tokens/access_token.ex index e44a49d1..64a5808a 100644 --- a/lib/ex_oauth2_provider/access_tokens/access_token.ex +++ b/lib/ex_oauth2_provider/access_tokens/access_token.ex @@ -130,7 +130,7 @@ defmodule ExOauth2Provider.AccessTokens.AccessToken do opts = Keyword.put(opts, :resource_owner_id, resource_owner_id(opts[:resource_owner])) case Config.access_token_generator(config) do - nil -> Utils.generate_token(opts) + nil -> Utils.generate_token(opts) {module, method} -> apply(module, method, [opts]) end end @@ -139,6 +139,7 @@ defmodule ExOauth2Provider.AccessTokens.AccessToken do defp resource_owner_id(_), do: nil defp put_previous_refresh_token(changeset, nil), do: changeset + defp put_previous_refresh_token(changeset, refresh_token), do: Changeset.change(changeset, %{previous_refresh_token: refresh_token.refresh_token}) @@ -147,5 +148,6 @@ defmodule ExOauth2Provider.AccessTokens.AccessToken do |> Changeset.change(%{refresh_token: Utils.generate_token()}) |> Changeset.validate_required([:refresh_token]) end + defp put_refresh_token(changeset, _), do: changeset end diff --git a/lib/ex_oauth2_provider/access_tokens/access_tokens.ex b/lib/ex_oauth2_provider/access_tokens/access_tokens.ex index bc35d24e..1a90fa01 100644 --- a/lib/ex_oauth2_provider/access_tokens/access_tokens.ex +++ b/lib/ex_oauth2_provider/access_tokens/access_tokens.ex @@ -120,7 +120,10 @@ defmodule ExOauth2Provider.AccessTokens do queryable |> where([a], is_nil(a.revoked_at)) - |> where([a], is_nil(a.expires_in) or datetime_add(a.inserted_at, a.expires_in, "second") > ^now) + |> where( + [a], + is_nil(a.expires_in) or datetime_add(a.inserted_at, a.expires_in, "second") > ^now + ) |> order_by([a], desc: a.inserted_at, desc: :id) |> Config.repo(config).all() |> Enum.filter(&is_accessible?/1) @@ -128,20 +131,26 @@ defmodule ExOauth2Provider.AccessTokens do end defp maybe_build_scopes(_application, scopes, _config) when is_binary(scopes), do: scopes - defp maybe_build_scopes(%{scopes: server_scopes}, nil, config), do: Scopes.parse_default_scope_string(server_scopes, config) - defp maybe_build_scopes(_application, nil, config), do: Scopes.parse_default_scope_string(nil, config) + + defp maybe_build_scopes(%{scopes: server_scopes}, nil, config), + do: Scopes.parse_default_scope_string(server_scopes, config) + + defp maybe_build_scopes(_application, nil, config), + do: Scopes.parse_default_scope_string(nil, config) defp check_matching_scopes(tokens, scopes) when is_list(tokens) do Enum.find(tokens, nil, &check_matching_scopes(&1, scopes)) end + defp check_matching_scopes(nil, _), do: nil + defp check_matching_scopes(token, scopes) do - token_scopes = ScopesUtils.to_list(token.scopes) + token_scopes = ScopesUtils.to_list(token.scopes) request_scopes = ScopesUtils.to_list(scopes) case ScopesUtils.equal?(token_scopes, request_scopes) do true -> token - _ -> nil + _ -> nil end end @@ -159,7 +168,7 @@ defmodule ExOauth2Provider.AccessTokens do |> Config.access_token() |> where([a], a.resource_owner_id == ^resource_owner.id) |> where([a], is_nil(a.revoked_at)) - |> Config.repo(config).all() + |> Config.repo(config).all() end @doc """ @@ -176,7 +185,8 @@ defmodule ExOauth2Provider.AccessTokens do iex> create_token(resource_owner, %{expires_in: "invalid"}, otp_app: :my_app) {:error, %Ecto.Changeset{}} """ - @spec create_token(Schema.t(), map(), keyword()) :: {:ok, AccessToken.t()} | {:error, Changeset.t()} + @spec create_token(Schema.t(), map(), keyword()) :: + {:ok, AccessToken.t()} | {:error, Changeset.t()} def create_token(resource_owner, attrs \\ %{}, config \\ []) do config |> Config.access_token() @@ -187,7 +197,7 @@ defmodule ExOauth2Provider.AccessTokens do defp put_application(access_token, attrs) do case Map.get(attrs, :application) do - nil -> access_token + nil -> access_token application -> %{access_token | application: application} end end @@ -208,7 +218,8 @@ defmodule ExOauth2Provider.AccessTokens do iex> create_application_token(application, %{scopes: "read write"}, otp_app: :my_app) {:ok, %OauthAccessToken{}} """ - @spec create_application_token(Schema.t() | nil, map(), keyword()) :: {:ok, AccessToken.t()} | {:error, Changeset.t()} + @spec create_application_token(Schema.t() | nil, map(), keyword()) :: + {:ok, AccessToken.t()} | {:error, Changeset.t()} def create_application_token(application, attrs \\ %{}, config \\ []) do config |> Config.access_token() @@ -230,6 +241,7 @@ defmodule ExOauth2Provider.AccessTokens do """ @spec is_accessible?(AccessToken.t() | nil) :: boolean() def is_accessible?(nil), do: false + def is_accessible?(token) do !is_expired?(token) and !is_revoked?(token) end @@ -248,7 +260,15 @@ defmodule ExOauth2Provider.AccessTokens do @spec get_by_previous_refresh_token_for(AccessToken.t(), keyword()) :: AccessToken.t() | nil def get_by_previous_refresh_token_for(%{previous_refresh_token: nil}, _config), do: nil def get_by_previous_refresh_token_for(%{previous_refresh_token: ""}, _config), do: nil - def get_by_previous_refresh_token_for(%{previous_refresh_token: previous_refresh_token, resource_owner_id: resource_owner_id, application_id: application_id}, config) do + + def get_by_previous_refresh_token_for( + %{ + previous_refresh_token: previous_refresh_token, + resource_owner_id: resource_owner_id, + application_id: application_id + }, + config + ) do config |> Config.access_token() |> scope_belongs_to(:application_id, application_id) @@ -261,9 +281,11 @@ defmodule ExOauth2Provider.AccessTokens do defp scope_belongs_to(queryable, belongs_to_column, nil) do where(queryable, [x], is_nil(field(x, ^belongs_to_column))) end + defp scope_belongs_to(queryable, belongs_to_column, %{id: id}) do scope_belongs_to(queryable, belongs_to_column, id) end + defp scope_belongs_to(queryable, belongs_to_column, id) do where(queryable, [x], field(x, ^belongs_to_column) == ^id) end @@ -281,10 +303,16 @@ defmodule ExOauth2Provider.AccessTokens do iex> revoke_previous_refresh_token(invalid_data, otp_app: :my_app) {:error, %Ecto.Changeset{}} """ - @spec revoke_previous_refresh_token(AccessToken.t()) :: {:ok, AccessToken.t()} | {:error, Changeset.t()} + @spec revoke_previous_refresh_token(AccessToken.t()) :: + {:ok, AccessToken.t()} | {:error, Changeset.t()} def revoke_previous_refresh_token(access_token, config \\ []) - def revoke_previous_refresh_token(%{previous_refresh_token: ""} = access_token, _config), do: {:ok, access_token} - def revoke_previous_refresh_token(%{previous_refresh_token: nil} = access_token, _config), do: {:ok, access_token} + + def revoke_previous_refresh_token(%{previous_refresh_token: ""} = access_token, _config), + do: {:ok, access_token} + + def revoke_previous_refresh_token(%{previous_refresh_token: nil} = access_token, _config), + do: {:ok, access_token} + def revoke_previous_refresh_token(access_token, config) do access_token |> get_by_previous_refresh_token_for(config) diff --git a/lib/ex_oauth2_provider/applications/application.ex b/lib/ex_oauth2_provider/applications/application.ex index 217d7236..30ce419d 100644 --- a/lib/ex_oauth2_provider/applications/application.ex +++ b/lib/ex_oauth2_provider/applications/application.ex @@ -42,11 +42,11 @@ defmodule ExOauth2Provider.Applications.Application do @doc false def attrs() do [ - {:name, :string, [], null: false}, - {:uid, :string, [], null: false}, - {:secret, :string, [default: ""], null: false}, - {:redirect_uri, :string, [], null: false}, - {:scopes, :string, [default: ""], null: false}, + {:name, :string, [], null: false}, + {:uid, :string, [], null: false}, + {:secret, :string, [default: ""], null: false}, + {:redirect_uri, :string, [], null: false}, + {:scopes, :string, [default: ""], null: false} ] end @@ -67,7 +67,7 @@ defmodule ExOauth2Provider.Applications.Application do use ExOauth2Provider.Schema, unquote(config) # For Phoenix integrations - if Code.ensure_loaded?(Phoenix.Param), do: @derive {Phoenix.Param, key: :uid} + if Code.ensure_loaded?(Phoenix.Param), do: @derive({Phoenix.Param, key: :uid}) import unquote(__MODULE__), only: [application_fields: 0] end @@ -98,13 +98,13 @@ defmodule ExOauth2Provider.Applications.Application do defp validate_secret_not_nil(changeset) do case Changeset.get_field(changeset, :secret) do nil -> Changeset.add_error(changeset, :secret, "can't be blank") - _ -> changeset + _ -> changeset end end defp maybe_new_application_changeset(application, params, config) do case Ecto.get_meta(application, :state) do - :built -> new_application_changeset(application, params, config) + :built -> new_application_changeset(application, params, config) :loaded -> application end end @@ -127,18 +127,20 @@ defmodule ExOauth2Provider.Applications.Application do url |> RedirectURI.validate(config) |> case do - {:error, error} -> Changeset.add_error(changeset, :redirect_uri, error) - {:ok, _} -> changeset - end + {:error, error} -> Changeset.add_error(changeset, :redirect_uri, error) + {:ok, _} -> changeset + end end) end defp put_uid(%{changes: %{uid: _}} = changeset), do: changeset + defp put_uid(%{} = changeset) do Changeset.change(changeset, %{uid: Utils.generate_token()}) end defp put_secret(%{changes: %{secret: _}} = changeset), do: changeset + defp put_secret(%{} = changeset) do Changeset.change(changeset, %{secret: Utils.generate_token()}) end diff --git a/lib/ex_oauth2_provider/applications/applications.ex b/lib/ex_oauth2_provider/applications/applications.ex index dfb94186..5e810d60 100644 --- a/lib/ex_oauth2_provider/applications/applications.ex +++ b/lib/ex_oauth2_provider/applications/applications.ex @@ -151,7 +151,8 @@ defmodule ExOauth2Provider.Applications do {:error, %Ecto.Changeset{}} """ - @spec create_application(Schema.t(), map(), keyword()) :: {:ok, Application.t()} | {:error, Changeset.t()} + @spec create_application(Schema.t(), map(), keyword()) :: + {:ok, Application.t()} | {:error, Changeset.t()} def create_application(owner, attrs \\ %{}, config \\ []) do config |> Config.application() @@ -172,7 +173,8 @@ defmodule ExOauth2Provider.Applications do {:error, %Ecto.Changeset{}} """ - @spec update_application(Application.t(), map(), keyword()) :: {:ok, Application.t()} | {:error, Changeset.t()} + @spec update_application(Application.t(), map(), keyword()) :: + {:ok, Application.t()} | {:error, Changeset.t()} def update_application(application, attrs, config \\ []) do application |> Application.changeset(attrs, config) @@ -191,7 +193,8 @@ defmodule ExOauth2Provider.Applications do {:error, %Ecto.Changeset{}} """ - @spec delete_application(Application.t(), keyword()) :: {:ok, Application.t()} | {:error, Changeset.t()} + @spec delete_application(Application.t(), keyword()) :: + {:ok, Application.t()} | {:error, Changeset.t()} def delete_application(application, config \\ []) do Config.repo(config).delete(application) end @@ -205,11 +208,12 @@ defmodule ExOauth2Provider.Applications do {:ok, [ok: %OauthAccessToken{}]} """ - @spec revoke_all_access_tokens_for(Application.t(), Schema.t(), keyword()) :: {:ok, [ok: AccessToken.t()]} | {:error, any()} + @spec revoke_all_access_tokens_for(Application.t(), Schema.t(), keyword()) :: + {:ok, [ok: AccessToken.t()]} | {:error, any()} def revoke_all_access_tokens_for(application, resource_owner, config \\ []) do repo = Config.repo(config) - repo.transaction fn -> + repo.transaction(fn -> config |> Config.access_token() |> where([a], a.resource_owner_id == ^resource_owner.id) @@ -217,6 +221,6 @@ defmodule ExOauth2Provider.Applications do |> where([o], is_nil(o.revoked_at)) |> repo.all() |> Enum.map(&AccessTokens.revoke(&1, config)) - end + end) end end diff --git a/lib/ex_oauth2_provider/mixin/expirable.ex b/lib/ex_oauth2_provider/mixin/expirable.ex index 3ac8ceb8..e65235ea 100644 --- a/lib/ex_oauth2_provider/mixin/expirable.ex +++ b/lib/ex_oauth2_provider/mixin/expirable.ex @@ -18,7 +18,7 @@ defmodule ExOauth2Provider.Mixin.Expirable do @spec filter_expired(Schema.t()) :: Schema.t() | nil def filter_expired(data) do case is_expired?(data) do - true -> nil + true -> nil false -> data end end @@ -40,8 +40,9 @@ defmodule ExOauth2Provider.Mixin.Expirable do @spec is_expired?(Schema.t() | nil) :: boolean() def is_expired?(nil), do: true def is_expired?(%{expires_in: nil, inserted_at: _}), do: false + def is_expired?(%struct{expires_in: expires_in, inserted_at: inserted_at}) do - now = SchemaHelpers.__timestamp_for__(struct, :inserted_at) + now = SchemaHelpers.__timestamp_for__(struct, :inserted_at) type = now.__struct__() inserted_at diff --git a/lib/ex_oauth2_provider/mixin/revocable.ex b/lib/ex_oauth2_provider/mixin/revocable.ex index 9263a4b3..4eb3418c 100644 --- a/lib/ex_oauth2_provider/mixin/revocable.ex +++ b/lib/ex_oauth2_provider/mixin/revocable.ex @@ -42,6 +42,7 @@ defmodule ExOauth2Provider.Mixin.Revocable do defp revoke_query(%struct{revoked_at: nil} = data) do Changeset.change(data, revoked_at: SchemaHelpers.__timestamp_for__(struct, :revoked_at)) end + defp revoke_query(_data), do: nil @doc """ @@ -58,7 +59,7 @@ defmodule ExOauth2Provider.Mixin.Revocable do @spec filter_revoked(Schema.t()) :: Schema.t() | nil def filter_revoked(data) do case is_revoked?(data) do - true -> nil + true -> nil false -> data end end diff --git a/lib/ex_oauth2_provider/mixin/scopes.ex b/lib/ex_oauth2_provider/mixin/scopes.ex index 91666eab..30d17d65 100644 --- a/lib/ex_oauth2_provider/mixin/scopes.ex +++ b/lib/ex_oauth2_provider/mixin/scopes.ex @@ -5,18 +5,25 @@ defmodule ExOauth2Provider.Mixin.Scopes do @spec put_scopes(Changeset.t(), binary() | nil, keyword()) :: Changeset.t() def put_scopes(changeset, "", config), do: put_scopes(changeset, nil, config) + def put_scopes(changeset, default_server_scopes, config) do changeset |> Changeset.get_field(:scopes) |> is_empty() |> case do - true -> Changeset.change(changeset, %{scopes: parse_default_scope_string(default_server_scopes, config)}) - _ -> changeset + true -> + Changeset.change(changeset, %{ + scopes: parse_default_scope_string(default_server_scopes, config) + }) + + _ -> + changeset end end @spec validate_scopes(Changeset.t(), binary() | nil, keyword()) :: Changeset.t() def validate_scopes(changeset, "", config), do: validate_scopes(changeset, nil, config) + def validate_scopes(changeset, server_scopes, config) do server_scopes = permitted_scopes(server_scopes, config) @@ -24,8 +31,15 @@ defmodule ExOauth2Provider.Mixin.Scopes do |> Changeset.get_field(:scopes) |> can_use_scopes?(server_scopes, config) |> case do - true -> changeset - _ -> Changeset.add_error(changeset, :scopes, "not in permitted scopes list: #{inspect(server_scopes)}") + true -> + changeset + + _ -> + Changeset.add_error( + changeset, + :scopes, + "not in permitted scopes list: #{inspect(server_scopes)}" + ) end end @@ -35,11 +49,13 @@ defmodule ExOauth2Provider.Mixin.Scopes do @spec parse_default_scope_string(binary() | [binary()] | nil, keyword()) :: binary() def parse_default_scope_string(nil, config), do: parse_default_scope_string("", config) + def parse_default_scope_string(server_scopes, config) when is_binary(server_scopes) do server_scopes |> Scopes.to_list() |> parse_default_scope_string(config) end + def parse_default_scope_string(server_scopes, config) do server_scopes |> Scopes.default_to_server_scopes(config) @@ -52,9 +68,11 @@ defmodule ExOauth2Provider.Mixin.Scopes do |> Scopes.to_list() |> can_use_scopes?(server_scopes, config) end + defp can_use_scopes?(scopes, server_scopes, config) when is_binary(server_scopes) do can_use_scopes?(scopes, Scopes.to_list(server_scopes), config) end + defp can_use_scopes?(scopes, server_scopes, config) do server_scopes |> Scopes.default_to_server_scopes(config) @@ -63,6 +81,7 @@ defmodule ExOauth2Provider.Mixin.Scopes do defp permitted_scopes(nil, config), do: Config.server_scopes(config) + defp permitted_scopes(server_scopes, _config), do: server_scopes end diff --git a/lib/ex_oauth2_provider/oauth2/authorization.ex b/lib/ex_oauth2_provider/oauth2/authorization.ex index b470dd1e..a9e954c8 100644 --- a/lib/ex_oauth2_provider/oauth2/authorization.ex +++ b/lib/ex_oauth2_provider/oauth2/authorization.ex @@ -2,34 +2,45 @@ defmodule ExOauth2Provider.Authorization do @moduledoc """ Handler for dealing with generating access grants. """ - alias ExOauth2Provider.{ - Authorization.Utils, - Authorization.Utils.Response, - Config, - Utils.Error} + alias ExOauth2Provider.Authorization.Utils + alias ExOauth2Provider.Authorization.Utils.Response + alias ExOauth2Provider.Config + alias ExOauth2Provider.Utils.Error alias Ecto.Schema @doc """ Check ExOauth2Provider.Authorization.Code for usage. """ - @spec preauthorize(Schema.t(), map(), keyword()) :: Response.success() | Response.error() | Response.redirect() | Response.native_redirect() + @spec preauthorize(Schema.t(), map(), keyword()) :: + Response.success() | Response.error() | Response.redirect() | Response.native_redirect() def preauthorize(resource_owner, request, config \\ []) do case validate_response_type(request, config) do - {:error, :invalid_response_type} -> unsupported_response_type(resource_owner, request, config) - {:error, :missing_response_type} -> invalid_request(resource_owner, request, config) - {:ok, token_module} -> token_module.preauthorize(resource_owner, request, config) + {:error, :invalid_response_type} -> + unsupported_response_type(resource_owner, request, config) + + {:error, :missing_response_type} -> + invalid_request(resource_owner, request, config) + + {:ok, token_module} -> + token_module.preauthorize(resource_owner, request, config) end end @doc """ Check ExOauth2Provider.Authorization.Code for usage. """ - @spec authorize(Schema.t(), map(), keyword()) :: {:ok, binary()} | Response.error() | Response.redirect() | Response.native_redirect() + @spec authorize(Schema.t(), map(), keyword()) :: + {:ok, binary()} | Response.error() | Response.redirect() | Response.native_redirect() def authorize(resource_owner, request, config \\ []) do case validate_response_type(request, config) do - {:error, :invalid_response_type} -> unsupported_response_type(resource_owner, request, config) - {:error, :missing_response_type} -> invalid_request(resource_owner, request, config) - {:ok, token_module} -> token_module.authorize(resource_owner, request, config) + {:error, :invalid_response_type} -> + unsupported_response_type(resource_owner, request, config) + + {:error, :missing_response_type} -> + invalid_request(resource_owner, request, config) + + {:ok, token_module} -> + token_module.authorize(resource_owner, request, config) end end @@ -39,9 +50,14 @@ defmodule ExOauth2Provider.Authorization do @spec deny(Schema.t(), map(), keyword()) :: Response.error() | Response.redirect() def deny(resource_owner, request, config \\ []) do case validate_response_type(request, config) do - {:error, :invalid_response_type} -> unsupported_response_type(resource_owner, request, config) - {:error, :missing_response_type} -> invalid_request(resource_owner, request, config) - {:ok, token_module} -> token_module.deny(resource_owner, request, config) + {:error, :invalid_response_type} -> + unsupported_response_type(resource_owner, request, config) + + {:error, :missing_response_type} -> + invalid_request(resource_owner, request, config) + + {:ok, token_module} -> + token_module.deny(resource_owner, request, config) end end @@ -67,6 +83,7 @@ defmodule ExOauth2Provider.Authorization do mod -> {:ok, mod} end end + defp validate_response_type(_, _config), do: {:error, :missing_response_type} defp response_type_to_grant_flow("code"), do: "authorization_code" @@ -77,7 +94,7 @@ defmodule ExOauth2Provider.Authorization do |> Config.grant_flows() |> flow_can_be_used?(grant_flow) |> case do - true -> flow_to_mod(grant_flow) + true -> flow_to_mod(grant_flow) false -> nil end end diff --git a/lib/ex_oauth2_provider/oauth2/authorization/strategy/code.ex b/lib/ex_oauth2_provider/oauth2/authorization/strategy/code.ex index 2b239fcd..7b4952e2 100644 --- a/lib/ex_oauth2_provider/oauth2/authorization/strategy/code.ex +++ b/lib/ex_oauth2_provider/oauth2/authorization/strategy/code.ex @@ -63,7 +63,9 @@ defmodule ExOauth2Provider.Authorization.Code do Authorization.Utils.Response, RedirectURI, Scopes, - Utils.Error} + Utils.Error + } + alias Ecto.Schema @doc """ @@ -85,7 +87,8 @@ defmodule ExOauth2Provider.Authorization.Code do {:redirect, redirect_uri} # Redirect {:native_redirect, %{code: code}} # Redirect to :show page """ - @spec preauthorize(Schema.t(), map(), keyword()) :: Response.success() | Response.error() | Response.redirect() | Response.native_redirect() + @spec preauthorize(Schema.t(), map(), keyword()) :: + Response.success() | Response.error() | Response.redirect() | Response.native_redirect() def preauthorize(resource_owner, request, config \\ []) do resource_owner |> Utils.prehandle_request(request, config) @@ -96,15 +99,24 @@ defmodule ExOauth2Provider.Authorization.Code do end defp check_previous_authorization({:error, params}, _config), do: {:error, params} - defp check_previous_authorization({:ok, %{resource_owner: resource_owner, client: application, request: %{"scope" => scopes}} = params}, config) do + + defp check_previous_authorization( + {:ok, + %{resource_owner: resource_owner, client: application, request: %{"scope" => scopes}} = + params}, + config + ) do case AccessTokens.get_token_for(resource_owner, application, scopes, config) do - nil -> {:ok, params} + nil -> {:ok, params} token -> {:ok, Map.put(params, :access_token, token)} end end defp reissue_grant({:error, params}, _config), do: {:error, params} - defp reissue_grant({:ok, %{access_token: _access_token} = params}, config), do: issue_grant({:ok, params}, config) + + defp reissue_grant({:ok, %{access_token: _access_token} = params}, config), + do: issue_grant({:ok, params}, config) + defp reissue_grant({:ok, params}, _config), do: {:ok, params} @doc """ @@ -129,7 +141,8 @@ defmodule ExOauth2Provider.Authorization.Code do {:redirect, redirect_uri} # Redirect {:native_redirect, %{code: code}} # Redirect to :show page """ - @spec authorize(Schema.t(), map(), keyword()) :: Response.success() | Response.error() | Response.redirect() | Response.native_redirect() + @spec authorize(Schema.t(), map(), keyword()) :: + Response.success() | Response.error() | Response.redirect() | Response.native_redirect() def authorize(resource_owner, request, config \\ []) do resource_owner |> Utils.prehandle_request(request, config) @@ -139,20 +152,24 @@ defmodule ExOauth2Provider.Authorization.Code do end defp issue_grant({:error, %{error: _error} = params}, _config), do: {:error, params} - defp issue_grant({:ok, %{resource_owner: resource_owner, client: application, request: request} = params}, config) do + + defp issue_grant( + {:ok, %{resource_owner: resource_owner, client: application, request: request} = params}, + config + ) do grant_params = request |> Map.take(["redirect_uri", "scope"]) |> Map.new(fn {k, v} -> case k do "scope" -> {:scopes, v} - _ -> {String.to_atom(k), v} + _ -> {String.to_atom(k), v} end end) |> Map.put(:expires_in, Config.authorization_code_expires_in(config)) case AccessGrants.create_grant(resource_owner, application, grant_params, config) do - {:ok, grant} -> {:ok, Map.put(params, :grant, grant)} + {:ok, grant} -> {:ok, Map.put(params, :grant, grant)} {:error, error} -> Error.add_error({:ok, params}, error) end end @@ -183,6 +200,7 @@ defmodule ExOauth2Provider.Authorization.Code do end defp validate_request({:error, params}, _config), do: {:error, params} + defp validate_request({:ok, params}, config) do {:ok, params} |> validate_resource_owner() @@ -193,26 +211,32 @@ defmodule ExOauth2Provider.Authorization.Code do defp validate_resource_owner({:ok, %{resource_owner: resource_owner} = params}) do case resource_owner do record when is_map(record) -> {:ok, params} - _ -> Error.add_error({:ok, params}, Error.invalid_request()) + _ -> Error.add_error({:ok, params}, Error.invalid_request()) end end defp validate_scopes({:error, params}, _config), do: {:error, params} + defp validate_scopes({:ok, %{request: %{"scope" => scopes}, client: client} = params}, config) do - scopes = Scopes.to_list(scopes) + scopes = Scopes.to_list(scopes) + server_scopes = client.scopes |> Scopes.to_list() |> Scopes.default_to_server_scopes(config) case Scopes.all?(server_scopes, scopes) do - true -> {:ok, params} + true -> {:ok, params} false -> Error.add_error({:ok, params}, Error.invalid_scopes()) end end defp validate_redirect_uri({:error, params}, _config), do: {:error, params} - defp validate_redirect_uri({:ok, %{request: %{"redirect_uri" => redirect_uri}, client: client} = params}, config) do + + defp validate_redirect_uri( + {:ok, %{request: %{"redirect_uri" => redirect_uri}, client: client} = params}, + config + ) do cond do RedirectURI.native_redirect_uri?(redirect_uri, config) -> {:ok, params} @@ -224,5 +248,7 @@ defmodule ExOauth2Provider.Authorization.Code do Error.add_error({:ok, params}, Error.invalid_redirect_uri()) end end - defp validate_redirect_uri({:ok, params}, _config), do: Error.add_error({:ok, params}, Error.invalid_request()) + + defp validate_redirect_uri({:ok, params}, _config), + do: Error.add_error({:ok, params}, Error.invalid_request()) end diff --git a/lib/ex_oauth2_provider/oauth2/authorization/utils.ex b/lib/ex_oauth2_provider/oauth2/authorization/utils.ex index 998c0beb..e90b6dee 100644 --- a/lib/ex_oauth2_provider/oauth2/authorization/utils.ex +++ b/lib/ex_oauth2_provider/oauth2/authorization/utils.ex @@ -19,20 +19,24 @@ defmodule ExOauth2Provider.Authorization.Utils do defp load_client({:ok, %{request: %{"client_id" => client_id}} = params}, config) do case Applications.get_application(client_id, config) do - nil -> Error.add_error({:ok, params}, Error.invalid_client()) + nil -> Error.add_error({:ok, params}, Error.invalid_client()) client -> {:ok, Map.put(params, :client, client)} end end - defp load_client({:ok, params}, _config), do: Error.add_error({:ok, params}, Error.invalid_request()) + + defp load_client({:ok, params}, _config), + do: Error.add_error({:ok, params}, Error.invalid_request()) defp set_defaults({:error, params}), do: {:error, params} + defp set_defaults({:ok, %{request: request, client: client} = params}) do [redirect_uri | _rest] = String.split(client.redirect_uri) - request = Map.new() - |> Map.put("redirect_uri", redirect_uri) - |> Map.put("scope", nil) - |> Map.merge(request) + request = + Map.new() + |> Map.put("redirect_uri", redirect_uri) + |> Map.put("scope", nil) + |> Map.merge(request) {:ok, Map.put(params, :request, request)} end diff --git a/lib/ex_oauth2_provider/oauth2/authorization/utils/response.ex b/lib/ex_oauth2_provider/oauth2/authorization/utils/response.ex index b6e6be3c..dc541764 100644 --- a/lib/ex_oauth2_provider/oauth2/authorization/utils/response.ex +++ b/lib/ex_oauth2_provider/oauth2/authorization/utils/response.ex @@ -11,29 +11,41 @@ defmodule ExOauth2Provider.Authorization.Utils.Response do @doc false @spec error_response({:error, map()}, keyword()) :: error() | redirect() | native_redirect() - def error_response({:error, %{error: error} = params}, config), do: build_response(params, error, config) + def error_response({:error, %{error: error} = params}, config), + do: build_response(params, error, config) @doc false - @spec preauthorize_response({:ok, map()} | {:error, map()}, keyword()) :: success() | error() | redirect() | native_redirect() - def preauthorize_response({:ok, %{grant: grant} = params}, config), do: build_response(params, %{code: grant.token}, config) - def preauthorize_response({:ok, %{client: client, request: %{"scope" => scopes}}}, _config), do: {:ok, client, Scopes.to_list(scopes)} - def preauthorize_response({:error, %{error: error} = params}, config), do: build_response(params, error, config) + @spec preauthorize_response({:ok, map()} | {:error, map()}, keyword()) :: + success() | error() | redirect() | native_redirect() + def preauthorize_response({:ok, %{grant: grant} = params}, config), + do: build_response(params, %{code: grant.token}, config) + + def preauthorize_response({:ok, %{client: client, request: %{"scope" => scopes}}}, _config), + do: {:ok, client, Scopes.to_list(scopes)} + + def preauthorize_response({:error, %{error: error} = params}, config), + do: build_response(params, error, config) @doc false - @spec authorize_response({:ok, map()} | {:error, map()}, keyword()) :: success() | error() | redirect() | native_redirect() - def authorize_response({:ok, %{grant: grant} = params}, config), do: build_response(params, %{code: grant.token}, config) - def authorize_response({:error, %{error: error} = params}, config), do: build_response(params, error, config) + @spec authorize_response({:ok, map()} | {:error, map()}, keyword()) :: + success() | error() | redirect() | native_redirect() + def authorize_response({:ok, %{grant: grant} = params}, config), + do: build_response(params, %{code: grant.token}, config) + + def authorize_response({:error, %{error: error} = params}, config), + do: build_response(params, error, config) @doc false @spec deny_response({:error, map()}, keyword()) :: error() | redirect() | native_redirect() - def deny_response({:error, %{error: error} = params}, config), do: build_response(params, error, config) + def deny_response({:error, %{error: error} = params}, config), + do: build_response(params, error, config) defp build_response(%{request: request} = params, payload, config) do payload = add_state(payload, request) case can_redirect?(params, config) do true -> build_redirect_response(params, payload, config) - _ -> build_standard_response(params, payload) + _ -> build_standard_response(params, payload) end end @@ -52,23 +64,32 @@ defmodule ExOauth2Provider.Authorization.Utils.Response do defp build_redirect_response(%{request: %{"redirect_uri" => redirect_uri}}, payload, config) do case RedirectURI.native_redirect_uri?(redirect_uri, config) do true -> {:native_redirect, payload} - _ -> {:redirect, RedirectURI.uri_with_query(redirect_uri, payload)} + _ -> {:redirect, RedirectURI.uri_with_query(redirect_uri, payload)} end end defp build_standard_response(%{grant: _}, payload) do {:ok, payload} end + defp build_standard_response(%{error: error, error_http_status: error_http_status}, _) do {:error, error, error_http_status} end - defp build_standard_response(%{error: error}, _) do # For DB errors + + # For DB errors + defp build_standard_response(%{error: error}, _) do {:error, error, :bad_request} end defp can_redirect?(%{error: %{error: :invalid_redirect_uri}}, _config), do: false defp can_redirect?(%{error: %{error: :invalid_client}}, _config), do: false - defp can_redirect?(%{error: %{error: _error}, request: %{"redirect_uri" => redirect_uri}}, config), do: !RedirectURI.native_redirect_uri?(redirect_uri, config) + + defp can_redirect?( + %{error: %{error: _error}, request: %{"redirect_uri" => redirect_uri}}, + config + ), + do: !RedirectURI.native_redirect_uri?(redirect_uri, config) + defp can_redirect?(%{error: _}, _config), do: false defp can_redirect?(%{request: %{}}, _config), do: true end diff --git a/lib/ex_oauth2_provider/oauth2/token.ex b/lib/ex_oauth2_provider/oauth2/token.ex index a47bce74..79a2ab7a 100644 --- a/lib/ex_oauth2_provider/oauth2/token.ex +++ b/lib/ex_oauth2_provider/oauth2/token.ex @@ -2,10 +2,9 @@ defmodule ExOauth2Provider.Token do @moduledoc """ Handler for dealing with generating access tokens. """ - alias ExOauth2Provider.{ - Config, - Token.Revoke, - Utils.Error} + alias ExOauth2Provider.Config + alias ExOauth2Provider.Token.Revoke + alias ExOauth2Provider.Utils.Error alias Ecto.Schema @doc """ @@ -28,7 +27,7 @@ defmodule ExOauth2Provider.Token do case validate_grant_type(request, config) do {:error, :invalid_grant_type} -> Error.unsupported_grant_type() {:error, :missing_grant_type} -> Error.invalid_request() - {:ok, token_module} -> token_module.grant(request, config) + {:ok, token_module} -> token_module.grant(request, config) end end @@ -40,6 +39,7 @@ defmodule ExOauth2Provider.Token do mod -> {:ok, mod} end end + defp validate_grant_type(_, _config), do: {:error, :missing_grant_type} defp fetch_module(type, config) do @@ -47,15 +47,17 @@ defmodule ExOauth2Provider.Token do |> Config.grant_flows() |> grant_type_can_be_used?(type, config) |> case do - true -> grant_type_to_mod(type) + true -> grant_type_to_mod(type) false -> nil end end defp grant_type_can_be_used?(_, "refresh_token", config), do: Config.use_refresh_token?(config) + defp grant_type_can_be_used?(_, "password", config), do: not is_nil(Config.password_auth(config)) + defp grant_type_can_be_used?(grant_flows, grant_type, _config) do Enum.member?(grant_flows, grant_type) end diff --git a/lib/ex_oauth2_provider/oauth2/token/strategy/authorization_code.ex b/lib/ex_oauth2_provider/oauth2/token/strategy/authorization_code.ex index d1c1abe7..ce4fcf5f 100644 --- a/lib/ex_oauth2_provider/oauth2/token/strategy/authorization_code.ex +++ b/lib/ex_oauth2_provider/oauth2/token/strategy/authorization_code.ex @@ -8,7 +8,8 @@ defmodule ExOauth2Provider.Token.AuthorizationCode do Config, Token.Utils, Token.Utils.Response, - Utils.Error} + Utils.Error + } @doc """ Will grant access token by client credentials. @@ -37,19 +38,24 @@ defmodule ExOauth2Provider.Token.AuthorizationCode do end defp issue_access_token_by_grant({:error, params}, _config), do: {:error, params} - defp issue_access_token_by_grant({:ok, %{access_grant: access_grant, request: _} = params}, config) do + + defp issue_access_token_by_grant( + {:ok, %{access_grant: access_grant, request: _} = params}, + config + ) do token_params = %{use_refresh_token: Config.use_refresh_token?(config)} - result = Config.repo(config).transaction(fn -> - access_grant - |> revoke_grant(config) - |> maybe_create_access_token(token_params, config) - end) + result = + Config.repo(config).transaction(fn -> + access_grant + |> revoke_grant(config) + |> maybe_create_access_token(token_params, config) + end) case result do - {:ok, {:error, error}} -> Error.add_error({:ok, params}, error) + {:ok, {:error, error}} -> Error.add_error({:ok, params}, error) {:ok, {:ok, access_token}} -> {:ok, Map.put(params, :access_token, access_token)} - {:error, error} -> Error.add_error({:ok, params}, error) + {:error, error} -> Error.add_error({:ok, params}, error) end end @@ -57,36 +63,52 @@ defmodule ExOauth2Provider.Token.AuthorizationCode do do: AccessGrants.revoke(access_grant, config) defp maybe_create_access_token({:error, _} = error, _token_params, _config), do: error - defp maybe_create_access_token({:ok, %{resource_owner: resource_owner, application: application, scopes: scopes}}, token_params, config) do + + defp maybe_create_access_token( + {:ok, %{resource_owner: resource_owner, application: application, scopes: scopes}}, + token_params, + config + ) do token_params = Map.merge(token_params, %{scopes: scopes, application: application}) resource_owner |> AccessTokens.get_token_for(application, scopes, config) |> case do - nil -> AccessTokens.create_token(resource_owner, token_params, config) + nil -> AccessTokens.create_token(resource_owner, token_params, config) access_token -> {:ok, access_token} end end - defp load_active_access_grant({:ok, %{client: client, request: %{"code" => code}} = params}, config) do + defp load_active_access_grant( + {:ok, %{client: client, request: %{"code" => code}} = params}, + config + ) do client |> AccessGrants.get_active_grant_for(code, config) |> Config.repo(config).preload(:resource_owner) |> Config.repo(config).preload(:application) |> case do - nil -> Error.add_error({:ok, params}, Error.invalid_grant()) + nil -> Error.add_error({:ok, params}, Error.invalid_grant()) access_grant -> {:ok, Map.put(params, :access_grant, access_grant)} end end - defp load_active_access_grant({:ok, params}, _config), do: Error.add_error({:ok, params}, Error.invalid_grant()) + + defp load_active_access_grant({:ok, params}, _config), + do: Error.add_error({:ok, params}, Error.invalid_grant()) + defp load_active_access_grant({:error, error}, _config), do: {:error, error} defp validate_redirect_uri({:error, params}), do: {:error, params} - defp validate_redirect_uri({:ok, %{request: %{"redirect_uri" => redirect_uri}, access_grant: grant} = params}) do + + defp validate_redirect_uri( + {:ok, %{request: %{"redirect_uri" => redirect_uri}, access_grant: grant} = params} + ) do case grant.redirect_uri == redirect_uri do - true -> {:ok, params} + true -> {:ok, params} false -> Error.add_error({:ok, params}, Error.invalid_grant()) end end - defp validate_redirect_uri({:ok, params}), do: Error.add_error({:ok, params}, Error.invalid_grant()) + + defp validate_redirect_uri({:ok, params}), + do: Error.add_error({:ok, params}, Error.invalid_grant()) end diff --git a/lib/ex_oauth2_provider/oauth2/token/strategy/client_credentials.ex b/lib/ex_oauth2_provider/oauth2/token/strategy/client_credentials.ex index 4da262bb..7447c3a0 100644 --- a/lib/ex_oauth2_provider/oauth2/token/strategy/client_credentials.ex +++ b/lib/ex_oauth2_provider/oauth2/token/strategy/client_credentials.ex @@ -6,7 +6,8 @@ defmodule ExOauth2Provider.Token.ClientCredentials do AccessTokens, Token.Utils, Token.Utils.Response, - Utils.Error} + Utils.Error + } @doc """ Will grant access token by client credentials. @@ -31,22 +32,28 @@ defmodule ExOauth2Provider.Token.ClientCredentials do end defp issue_access_token_by_creds({:error, params}, _config), do: {:error, params} - defp issue_access_token_by_creds({:ok, %{client: application, request: request} = params}, config) do + + defp issue_access_token_by_creds( + {:ok, %{client: application, request: request} = params}, + config + ) do scopes = request["scope"] + token_params = %{ - use_refresh_token: false, # client_credentials MUST NOT use refresh tokens + # client_credentials MUST NOT use refresh tokens + use_refresh_token: false, scopes: scopes } application |> AccessTokens.get_application_token_for(scopes, config) |> case do - nil -> AccessTokens.create_application_token(application, token_params, config) + nil -> AccessTokens.create_application_token(application, token_params, config) access_token -> {:ok, access_token} end |> case do {:ok, access_token} -> {:ok, Map.merge(params, %{access_token: access_token})} - {:error, error} -> Error.add_error({:ok, params}, error) + {:error, error} -> Error.add_error({:ok, params}, error) end end end diff --git a/lib/ex_oauth2_provider/oauth2/token/strategy/password.ex b/lib/ex_oauth2_provider/oauth2/token/strategy/password.ex index f11eb39e..c98330ba 100644 --- a/lib/ex_oauth2_provider/oauth2/token/strategy/password.ex +++ b/lib/ex_oauth2_provider/oauth2/token/strategy/password.ex @@ -8,7 +8,8 @@ defmodule ExOauth2Provider.Token.Password do Scopes, Token.Utils, Token.Utils.Response, - Utils.Error} + Utils.Error + } @doc """ Will grant access token by password authentication. @@ -41,50 +42,76 @@ defmodule ExOauth2Provider.Token.Password do defp get_password_auth_method({:ok, params}, config) do case Config.password_auth(config) do {module, method} -> {:ok, Map.put(params, :password_auth, {module, method})} - _ -> Error.add_error({:ok, params}, Error.unsupported_grant_type()) + _ -> Error.add_error({:ok, params}, Error.unsupported_grant_type()) end end defp load_resource_owner({:error, params}), do: {:error, params} - defp load_resource_owner({:ok, %{password_auth: {module, method}, request: %{"username" => username, "password" => password}} = params}) do + + defp load_resource_owner( + {:ok, + %{ + password_auth: {module, method}, + request: %{"username" => username, "password" => password} + } = params} + ) do case apply(module, method, [username, password]) do {:ok, resource_owner} -> {:ok, Map.put(params, :resource_owner, resource_owner)} {:error, reason} -> - {:error, Map.merge(params, %{error: :unauthorized, error_description: reason, error_http_status: :unauthorized})} + {:error, + Map.merge(params, %{ + error: :unauthorized, + error_description: reason, + error_http_status: :unauthorized + })} end end - defp load_resource_owner({:ok, params}), do: Error.add_error({:ok, params}, Error.invalid_request()) + + defp load_resource_owner({:ok, params}), + do: Error.add_error({:ok, params}, Error.invalid_request()) defp issue_access_token({:error, params}, _config), do: {:error, params} - defp issue_access_token({:ok, %{client: application, resource_owner: resource_owner, request: request} = params}, config) do + + defp issue_access_token( + {:ok, %{client: application, resource_owner: resource_owner, request: request} = params}, + config + ) do scopes = request["scope"] - token_params = %{use_refresh_token: Config.use_refresh_token?(config), scopes: scopes, application: application} + + token_params = %{ + use_refresh_token: Config.use_refresh_token?(config), + scopes: scopes, + application: application + } resource_owner |> AccessTokens.get_token_for(application, scopes, config) |> case do - nil -> AccessTokens.create_token(resource_owner, token_params, config) + nil -> AccessTokens.create_token(resource_owner, token_params, config) access_token -> {:ok, access_token} end |> case do {:ok, access_token} -> {:ok, Map.merge(params, %{access_token: access_token})} - {:error, error} -> Error.add_error({:ok, params}, error) + {:error, error} -> Error.add_error({:ok, params}, error) end end defp set_defaults({:error, params}), do: {:error, params} + defp set_defaults({:ok, %{request: request, client: client} = params}) do - scopes = Map.get(params.request, "scope", client.scopes) + scopes = Map.get(params.request, "scope", client.scopes) request = Map.put(request, "scope", scopes) {:ok, Map.put(params, :request, request)} end defp validate_scopes({:error, params}, _config), do: {:error, params} + defp validate_scopes({:ok, %{request: %{"scope" => scopes}, client: client} = params}, config) do - scopes = Scopes.to_list(scopes) + scopes = Scopes.to_list(scopes) + server_scopes = client.scopes |> Scopes.to_list() diff --git a/lib/ex_oauth2_provider/oauth2/token/strategy/refresh_token.ex b/lib/ex_oauth2_provider/oauth2/token/strategy/refresh_token.ex index dc4df7cf..050f0113 100644 --- a/lib/ex_oauth2_provider/oauth2/token/strategy/refresh_token.ex +++ b/lib/ex_oauth2_provider/oauth2/token/strategy/refresh_token.ex @@ -8,7 +8,8 @@ defmodule ExOauth2Provider.Token.RefreshToken do Config, Token.Utils, Token.Utils.Response, - Utils.Error} + Utils.Error + } @doc """ Will grant access token by refresh token. @@ -34,7 +35,10 @@ defmodule ExOauth2Provider.Token.RefreshToken do |> Response.response(config) end - defp load_access_token_by_refresh_token({:ok, %{client: client, request: %{"refresh_token" => refresh_token}} = params}, config) do + defp load_access_token_by_refresh_token( + {:ok, %{client: client, request: %{"refresh_token" => refresh_token}} = params}, + config + ) do access_token = client |> AccessTokens.get_by_refresh_token_for(refresh_token, config) @@ -42,29 +46,39 @@ defmodule ExOauth2Provider.Token.RefreshToken do |> Config.repo(config).preload(:application) case access_token do - nil -> Error.add_error({:ok, params}, Error.invalid_request()) + nil -> Error.add_error({:ok, params}, Error.invalid_request()) access_token -> {:ok, Map.put(params, :refresh_token, access_token)} end end - defp load_access_token_by_refresh_token(params, _config), do: Error.add_error(params, Error.invalid_request()) + + defp load_access_token_by_refresh_token(params, _config), + do: Error.add_error(params, Error.invalid_request()) defp issue_access_token_by_refresh_token({:error, params}, _config), do: {:error, params} - defp issue_access_token_by_refresh_token({:ok, %{refresh_token: refresh_token, request: _} = params}, config) do - result = Config.repo(config).transaction(fn -> - token_params = token_params(refresh_token, config) - - refresh_token - |> revoke_access_token(config) - |> case do - {:ok, %{resource_owner: resource_owner}} -> AccessTokens.create_token(resource_owner, token_params, config) - {:error, error} -> {:error, error} - end - end) + + defp issue_access_token_by_refresh_token( + {:ok, %{refresh_token: refresh_token, request: _} = params}, + config + ) do + result = + Config.repo(config).transaction(fn -> + token_params = token_params(refresh_token, config) + + refresh_token + |> revoke_access_token(config) + |> case do + {:ok, %{resource_owner: resource_owner}} -> + AccessTokens.create_token(resource_owner, token_params, config) + + {:error, error} -> + {:error, error} + end + end) case result do - {:ok, {:error, error}} -> Error.add_error({:ok, params}, error) + {:ok, {:error, error}} -> Error.add_error({:ok, params}, error) {:ok, {:ok, access_token}} -> {:ok, Map.merge(params, %{access_token: access_token})} - {:error, error} -> Error.add_error({:ok, params}, error) + {:error, error} -> Error.add_error({:ok, params}, error) end end @@ -72,7 +86,7 @@ defmodule ExOauth2Provider.Token.RefreshToken do params = %{scopes: scopes, application: application, use_refresh_token: true} case Config.refresh_token_revoked_on_use?(config) do - true -> Map.put(params, :previous_refresh_token, refresh_token) + true -> Map.put(params, :previous_refresh_token, refresh_token) false -> params end end diff --git a/lib/ex_oauth2_provider/oauth2/token/strategy/revoke.ex b/lib/ex_oauth2_provider/oauth2/token/strategy/revoke.ex index 4fcc118b..5c0c03d1 100644 --- a/lib/ex_oauth2_provider/oauth2/token/strategy/revoke.ex +++ b/lib/ex_oauth2_provider/oauth2/token/strategy/revoke.ex @@ -7,7 +7,8 @@ defmodule ExOauth2Provider.Token.Revoke do Config, Token.Utils, Token.Utils.Response, - Utils.Error} + Utils.Error + } @doc """ Revokes access token. @@ -50,43 +51,50 @@ defmodule ExOauth2Provider.Token.Revoke do defp load_client_if_presented({:ok, %{request: %{"client_id" => _}} = params}, config), do: Utils.load_client({:ok, params}, config) + defp load_client_if_presented({:ok, params}, _config), do: {:ok, params} defp load_access_token({:error, %{error: _} = params}, _config), do: {:error, params} + defp load_access_token({:ok, %{request: %{"token" => _}} = params}, config) do {:ok, params} |> get_access_token(config) |> get_refresh_token(config) |> preload_token_associations(config) end - defp load_access_token({:ok, params}, _config), do: Error.add_error({:ok, params}, Error.invalid_request()) + + defp load_access_token({:ok, params}, _config), + do: Error.add_error({:ok, params}, Error.invalid_request()) defp get_access_token({:ok, %{request: %{"token" => token}} = params}, config) do token |> AccessTokens.get_by_token(config) |> case do - nil -> Error.add_error({:ok, params}, Error.invalid_request()) + nil -> Error.add_error({:ok, params}, Error.invalid_request()) access_token -> {:ok, Map.put(params, :access_token, access_token)} end end defp get_refresh_token({:ok, %{access_token: _} = params}, _config), do: {:ok, params} defp get_refresh_token({:error, %{error: _} = params}, _config), do: {:error, params} + defp get_refresh_token({:ok, %{request: %{"token" => token}} = params}, config) do token |> AccessTokens.get_by_refresh_token(config) |> case do - nil -> Error.add_error({:ok, params}, Error.invalid_request()) + nil -> Error.add_error({:ok, params}, Error.invalid_request()) access_token -> {:ok, Map.put(params, :access_token, access_token)} end end defp preload_token_associations({:error, params}, _config), do: {:error, params} + defp preload_token_associations({:ok, %{access_token: access_token} = params}, config) do {:ok, Map.put(params, :access_token, Config.repo(config).preload(access_token, :application))} end defp validate_request({:error, params}), do: {:error, params} + defp validate_request({:ok, params}) do {:ok, params} |> validate_permissions() @@ -113,25 +121,37 @@ defmodule ExOauth2Provider.Token.Revoke do # https://tools.ietf.org/html/rfc7009 # Client is public, authentication unnecessary - defp validate_permissions({:ok, %{access_token: %{application_id: nil}} = params}), do: {:ok, params} + defp validate_permissions({:ok, %{access_token: %{application_id: nil}} = params}), + do: {:ok, params} + # Client is confidential, therefore client authentication & authorization is required - defp validate_permissions({:ok, %{access_token: %{application_id: _id}} = params}), do: validate_ownership({:ok, params}) + defp validate_permissions({:ok, %{access_token: %{application_id: _id}} = params}), + do: validate_ownership({:ok, params}) + + defp validate_ownership( + {:ok, + %{access_token: %{application_id: application_id}, client: %{id: client_id}} = params} + ) + when application_id == client_id, + do: {:ok, params} - defp validate_ownership({:ok, %{access_token: %{application_id: application_id}, client: %{id: client_id}} = params}) when application_id == client_id, do: {:ok, params} - defp validate_ownership({:ok, params}), do: Error.add_error({:ok, params}, Error.invalid_request()) + defp validate_ownership({:ok, params}), + do: Error.add_error({:ok, params}, Error.invalid_request()) defp validate_accessible({:error, params}), do: {:error, params} + defp validate_accessible({:ok, %{access_token: access_token} = params}) do case AccessTokens.is_accessible?(access_token) do - true -> {:ok, params} + true -> {:ok, params} false -> Error.add_error({:ok, params}, Error.invalid_request()) end end defp revoke_token({:error, params}, _config), do: {:error, params} + defp revoke_token({:ok, %{access_token: access_token} = params}, config) do case AccessTokens.revoke(access_token, config) do - {:ok, _} -> {:ok, params} + {:ok, _} -> {:ok, params} {:error, _} -> Error.add_error({:ok, params}, Error.invalid_request()) end end diff --git a/lib/ex_oauth2_provider/oauth2/token/utils.ex b/lib/ex_oauth2_provider/oauth2/token/utils.ex index 7fef0456..3868c498 100644 --- a/lib/ex_oauth2_provider/oauth2/token/utils.ex +++ b/lib/ex_oauth2_provider/oauth2/token/utils.ex @@ -9,10 +9,13 @@ defmodule ExOauth2Provider.Token.Utils do client_secret = Map.get(request, "client_secret", "") case Applications.load_application(client_id, client_secret, config) do - nil -> Error.add_error({:ok, params}, Error.invalid_client()) + nil -> Error.add_error({:ok, params}, Error.invalid_client()) client -> {:ok, Map.merge(params, %{client: client})} end end - def load_client({:ok, params}, _config), do: Error.add_error({:ok, params}, Error.invalid_request()) + + def load_client({:ok, params}, _config), + do: Error.add_error({:ok, params}, Error.invalid_request()) + def load_client({:error, params}, _config), do: {:error, params} end diff --git a/lib/ex_oauth2_provider/oauth2/token/utils/response.ex b/lib/ex_oauth2_provider/oauth2/token/utils/response.ex index ac266f09..86526caf 100644 --- a/lib/ex_oauth2_provider/oauth2/token/utils/response.ex +++ b/lib/ex_oauth2_provider/oauth2/token/utils/response.ex @@ -4,39 +4,52 @@ defmodule ExOauth2Provider.Token.Utils.Response do alias ExOauth2Provider.Config @doc false - @spec response({:ok, map()} | {:error, map()}, keyword()) :: {:ok, map()} | {:error, map(), atom()} - def response({:ok, %{access_token: token}}, config), do: build_response(%{access_token: token}, config) + @spec response({:ok, map()} | {:error, map()}, keyword()) :: + {:ok, map()} | {:error, map(), atom()} + def response({:ok, %{access_token: token}}, config), + do: build_response(%{access_token: token}, config) + def response({:error, %{error: _} = params}, config), do: build_response(params, config) @doc false - @spec revocation_response({:ok, map()} | {:error, map()}, keyword()) :: {:ok, map()} | {:error, map(), atom()} - def revocation_response({:error, %{should_return_error: true} = params}, config), do: response({:error, params}, config) + @spec revocation_response({:ok, map()} | {:error, map()}, keyword()) :: + {:ok, map()} | {:error, map(), atom()} + def revocation_response({:error, %{should_return_error: true} = params}, config), + do: response({:error, params}, config) + def revocation_response({_any, _params}, _config), do: {:ok, %{}} defp build_response(%{access_token: access_token}, config) do - body = %{access_token: access_token.token, - # Access Token type: Bearer. - # @see https://tools.ietf.org/html/rfc6750 - # The OAuth 2.0 Authorization Framework: Bearer Token Usage - token_type: "bearer", - expires_in: access_token.expires_in, - refresh_token: access_token.refresh_token, - scope: access_token.scopes, - created_at: access_token.inserted_at - } |> customize_access_token_response(access_token, config) + body = + %{ + access_token: access_token.token, + # Access Token type: Bearer. + # @see https://tools.ietf.org/html/rfc6750 + # The OAuth 2.0 Authorization Framework: Bearer Token Usage + token_type: "bearer", + expires_in: access_token.expires_in, + refresh_token: access_token.refresh_token, + scope: access_token.scopes, + created_at: access_token.inserted_at + } + |> customize_access_token_response(access_token, config) + {:ok, body} end + defp build_response(%{error: error, error_http_status: error_http_status}, _config) do {:error, error, error_http_status} end - defp build_response(%{error: error}, _config) do # For DB errors + + # For DB errors + defp build_response(%{error: error}, _config) do {:error, error, :bad_request} end defp customize_access_token_response(response_body, access_token, config) do case Config.access_token_response_body_handler(config) do {module, method} -> apply(module, method, [response_body, access_token]) - _ -> response_body + _ -> response_body end end end diff --git a/lib/ex_oauth2_provider/oauth2/utils/error.ex b/lib/ex_oauth2_provider/oauth2/utils/error.ex index 02bb83f7..960a089c 100644 --- a/lib/ex_oauth2_provider/oauth2/utils/error.ex +++ b/lib/ex_oauth2_provider/oauth2/utils/error.ex @@ -4,34 +4,43 @@ defmodule ExOauth2Provider.Utils.Error do @doc false @spec add_error({:ok, map()} | {:error, map()}, {:error, map(), atom()}) :: {:error, map()} def add_error({:error, params}, _), do: {:error, params} + def add_error({:ok, params}, {:error, error, http_status}) do {:error, Map.merge(params, %{error: error, error_http_status: http_status})} end @spec server_error() :: {:error, map(), atom()} def server_error do - msg = "The authorization server encountered an unexpected condition which prevented it from fulfilling the request." + msg = + "The authorization server encountered an unexpected condition which prevented it from fulfilling the request." + {:error, %{error: :internal_server_error, error_description: msg}, :internal_server_error} end @doc false @spec invalid_request() :: {:error, map(), atom()} def invalid_request do - msg = "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." + msg = + "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." + {:error, %{error: :invalid_request, error_description: msg}, :bad_request} end @doc false @spec invalid_client() :: {:error, map(), atom()} def invalid_client do - msg = "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + msg = + "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + {:error, %{error: :invalid_client, error_description: msg}, :unprocessable_entity} end @doc false @spec invalid_grant() :: {:error, map(), atom()} def invalid_grant do - msg = "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client." + msg = + "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client." + {:error, %{error: :invalid_grant, error_description: msg}, :unprocessable_entity} end diff --git a/lib/ex_oauth2_provider/plug.ex b/lib/ex_oauth2_provider/plug.ex index 9915c06b..a491f070 100644 --- a/lib/ex_oauth2_provider/plug.ex +++ b/lib/ex_oauth2_provider/plug.ex @@ -12,7 +12,8 @@ defmodule ExOauth2Provider.Plug do ExOauth2Provider.Plug.current_resource_owner(conn) """ - alias ExOauth2Provider.{Keys, AccessTokens.AccessToken} + alias ExOauth2Provider.AccessTokens.AccessToken + alias ExOauth2Provider.Keys alias Plug.Conn @doc """ diff --git a/lib/ex_oauth2_provider/plug/ensure_authenticated.ex b/lib/ex_oauth2_provider/plug/ensure_authenticated.ex index 10f31d44..5ada7fe1 100644 --- a/lib/ex_oauth2_provider/plug/ensure_authenticated.ex +++ b/lib/ex_oauth2_provider/plug/ensure_authenticated.ex @@ -36,6 +36,7 @@ defmodule ExOauth2Provider.Plug.EnsureAuthenticated do end defp handle_authentication({:ok, _}, conn, _opts), do: conn + defp handle_authentication({:error, reason}, %{params: params} = conn, opts) do params = Map.put(params, :reason, reason) module = Keyword.get(opts, :handler, ExOauth2Provider.Plug.ErrorHandler) diff --git a/lib/ex_oauth2_provider/plug/ensure_scopes.ex b/lib/ex_oauth2_provider/plug/ensure_scopes.ex index a61edaa0..177f916d 100644 --- a/lib/ex_oauth2_provider/plug/ensure_scopes.ex +++ b/lib/ex_oauth2_provider/plug/ensure_scopes.ex @@ -44,11 +44,12 @@ defmodule ExOauth2Provider.Plug.EnsureScopes do end defp check_scopes(nil, conn, opts), do: {:error, conn, opts} + defp check_scopes(token, conn, opts) do scopes_set = fetch_scopes(opts) case matches_any_scopes_set?(token, scopes_set) do - true -> {:ok, conn, opts} + true -> {:ok, conn, opts} false -> {:error, conn, opts} end end @@ -61,6 +62,7 @@ defmodule ExOauth2Provider.Plug.EnsureScopes do defp fetch_scopes(_opts, scopes), do: scopes defp matches_any_scopes_set?(_, []), do: true + defp matches_any_scopes_set?(access_token, scopes_sets) do Enum.any?(scopes_sets, &matches_scopes?(access_token, &1)) end @@ -72,6 +74,7 @@ defmodule ExOauth2Provider.Plug.EnsureScopes do end defp handle_error({:ok, conn, _}), do: conn + defp handle_error({:error, %Conn{params: params} = conn, opts}) do module = Keyword.get(opts, :handler, Plug.ErrorHandler) params = Map.put(params, :reason, :unauthorized) diff --git a/lib/ex_oauth2_provider/plug/error_handler.ex b/lib/ex_oauth2_provider/plug/error_handler.ex index 091c518c..083e33fb 100644 --- a/lib/ex_oauth2_provider/plug/error_handler.ex +++ b/lib/ex_oauth2_provider/plug/error_handler.ex @@ -36,10 +36,11 @@ defmodule ExOauth2Provider.Plug.ErrorHandler do |> Conn.configure_session(drop: true) |> Conn.put_resp_content_type("application/json") |> Conn.send_resp(status, Jason.encode!(%{errors: [msg]})) - rescue ArgumentError -> - conn - |> Conn.put_resp_content_type("application/json") - |> Conn.send_resp(status, Jason.encode!(%{errors: [msg]})) + rescue + ArgumentError -> + conn + |> Conn.put_resp_content_type("application/json") + |> Conn.send_resp(status, Jason.encode!(%{errors: [msg]})) end defp respond(conn, :html, status, msg) do @@ -47,22 +48,23 @@ defmodule ExOauth2Provider.Plug.ErrorHandler do |> Conn.configure_session(drop: true) |> Conn.put_resp_content_type("text/plain") |> Conn.send_resp(status, msg) - rescue ArgumentError -> - conn - |> Conn.put_resp_content_type("text/plain") - |> Conn.send_resp(status, msg) + rescue + ArgumentError -> + conn + |> Conn.put_resp_content_type("text/plain") + |> Conn.send_resp(status, msg) end defp response_type(conn) do accept = accept_header(conn) case Regex.match?(~r/json/, accept) do - true -> :json + true -> :json false -> :html end end - defp accept_header(conn) do + defp accept_header(conn) do conn |> Conn.get_req_header("accept") |> List.first() diff --git a/lib/ex_oauth2_provider/plug/verify_header.ex b/lib/ex_oauth2_provider/plug/verify_header.ex index 313ce901..7b82296f 100644 --- a/lib/ex_oauth2_provider/plug/verify_header.ex +++ b/lib/ex_oauth2_provider/plug/verify_header.ex @@ -35,8 +35,9 @@ defmodule ExOauth2Provider.Plug.VerifyHeader do end defp maybe_set_realm_option(nil, opts), do: opts + defp maybe_set_realm_option(realm, opts) do - realm = Regex.escape(realm) + realm = Regex.escape(realm) {:ok, realm_regex} = Regex.compile("#{realm}\:?\s+(.*)$", "i") Keyword.put(opts, :realm_regex, realm_regex) @@ -45,7 +46,7 @@ defmodule ExOauth2Provider.Plug.VerifyHeader do @doc false @spec call(Conn.t(), keyword()) :: Conn.t() def call(conn, opts) do - key = Keyword.get(opts, :key, :default) + key = Keyword.get(opts, :key, :default) config = Keyword.take(opts, [:otp_app]) conn @@ -63,17 +64,19 @@ defmodule ExOauth2Provider.Plug.VerifyHeader do defp do_fetch_token(_realm_regex, []), do: nil defp do_fetch_token(nil, [token | _tail]), do: String.trim(token) + defp do_fetch_token(realm_regex, [token | tail]) do trimmed_token = String.trim(token) case Regex.run(realm_regex, trimmed_token) do [_, match] -> String.trim(match) - _ -> do_fetch_token(realm_regex, tail) + _ -> do_fetch_token(realm_regex, tail) end end defp verify_token(nil, conn, _, _config), do: conn defp verify_token("", conn, _, _config), do: conn + defp verify_token(token, conn, key, config) do access_token = ExOauth2Provider.authenticate_token(token, config) diff --git a/lib/ex_oauth2_provider/redirect_uri.ex b/lib/ex_oauth2_provider/redirect_uri.ex index 5553ba26..8cbc95fb 100644 --- a/lib/ex_oauth2_provider/redirect_uri.ex +++ b/lib/ex_oauth2_provider/redirect_uri.ex @@ -2,7 +2,8 @@ defmodule ExOauth2Provider.RedirectURI do @moduledoc """ Functions for dealing with redirect uri. """ - alias ExOauth2Provider.{Config, Utils} + alias ExOauth2Provider.Config + alias ExOauth2Provider.Utils @doc """ Validates if a url can be used as a redirect_uri. diff --git a/lib/ex_oauth2_provider/schema.ex b/lib/ex_oauth2_provider/schema.ex index e9bc4e63..c9213144 100644 --- a/lib/ex_oauth2_provider/schema.ex +++ b/lib/ex_oauth2_provider/schema.ex @@ -23,7 +23,7 @@ defmodule ExOauth2Provider.Schema do {name, type, field_options, _migration_options} -> field(name, type, field_options) - end) + end) unquote(module).assocs() |> unquote(__MODULE__).__assocs_with_queryable__(@config) diff --git a/lib/mix/ex_oauth2_provider/config.ex b/lib/mix/ex_oauth2_provider/config.ex index 122586e9..09449ca4 100644 --- a/lib/mix/ex_oauth2_provider/config.ex +++ b/lib/mix/ex_oauth2_provider/config.ex @@ -7,5 +7,6 @@ defmodule Mix.ExOauth2Provider.Config do """ @spec gen(binary() | atom(), keyword()) :: binary() - def gen(context_app, opts), do: EEx.eval_string(@template, app: context_app, key: ExOauth2Provider, opts: opts) + def gen(context_app, opts), + do: EEx.eval_string(@template, app: context_app, key: ExOauth2Provider, opts: opts) end diff --git a/lib/mix/ex_oauth2_provider/migration.ex b/lib/mix/ex_oauth2_provider/migration.ex index 7c106c3e..6469d564 100644 --- a/lib/mix/ex_oauth2_provider/migration.ex +++ b/lib/mix/ex_oauth2_provider/migration.ex @@ -10,11 +10,13 @@ defmodule Mix.ExOauth2Provider.Migration do @spec create_migration_file(atom(), binary(), binary()) :: any() def create_migration_file(repo, name, content) do base_name = "#{Macro.underscore(name)}.exs" - path = + + path = repo |> Mix.EctoSQL.source_repo_priv() |> Path.join("migrations") |> maybe_create_directory() + timestamp = timestamp(path) path @@ -34,8 +36,13 @@ defmodule Mix.ExOauth2Provider.Migration do |> Path.join("*_#{base_name}") |> Path.wildcard() |> case do - [] -> path - _ -> Mix.raise("migration can't be created, there is already a migration file with name #{name}.") + [] -> + path + + _ -> + Mix.raise( + "migration can't be created, there is already a migration file with name #{name}." + ) end end @@ -47,7 +54,7 @@ defmodule Mix.ExOauth2Provider.Migration do |> Path.wildcard() |> case do [] -> timestamp - _ -> timestamp(path, seconds + 1) + _ -> timestamp(path, seconds + 1) end end @@ -61,7 +68,7 @@ defmodule Mix.ExOauth2Provider.Migration do "#{y}#{pad(m)}#{pad(d)}#{pad(hh)}#{pad(mm)}#{pad(ss)}" end - defp pad(i) when i < 10, do: << ?0, ?0 + i >> + defp pad(i) when i < 10, do: <> defp pad(i), do: to_string(i) @template """ @@ -84,15 +91,23 @@ defmodule Mix.ExOauth2Provider.Migration do end """ - alias ExOauth2Provider.{AccessGrants.AccessGrant, AccessTokens.AccessToken, Applications.Application} + alias ExOauth2Provider.{ + AccessGrants.AccessGrant, + AccessTokens.AccessToken, + Applications.Application + } - @schemas [{"applications", Application}, {"access_grants", AccessGrant}, {"access_tokens", AccessToken}] + @schemas [ + {"applications", Application}, + {"access_grants", AccessGrant}, + {"access_tokens", AccessToken} + ] @spec gen(binary(), binary(), map()) :: binary() def gen(name, namespace, %{repo: repo} = config) do schemas = for {table, module} <- @schemas, - do: schema(module, table, namespace, config) + do: schema(module, table, namespace, config) EEx.eval_string(@template, migration: %{repo: repo, name: name, schemas: schemas}) end @@ -103,10 +118,10 @@ defmodule Mix.ExOauth2Provider.Migration do |> Kernel.++(attrs_from_assocs(module.assocs(), namespace)) |> migration_attrs() - defaults = defaults(attrs) + defaults = defaults(attrs) {assocs, attrs} = partition_attrs(attrs) - table = "#{namespace}_#{table}" - indexes = migration_indexes(module.indexes(), table) + table = "#{namespace}_#{table}" + indexes = migration_indexes(module.indexes(), table) %{ table: table, @@ -127,10 +142,14 @@ defmodule Mix.ExOauth2Provider.Migration do defp attr_from_assoc({:belongs_to, name, :users}, _namespace) do {String.to_atom("#{name}_id"), {:references, :users}} end + defp attr_from_assoc({:belongs_to, name, table}, namespace) do {String.to_atom("#{name}_id"), {:references, String.to_atom("#{namespace}_#{table}")}} end - defp attr_from_assoc({:belongs_to, name, table, _defaults}, namespace), do: attr_from_assoc({:belongs_to, name, table}, namespace) + + defp attr_from_assoc({:belongs_to, name, table, _defaults}, namespace), + do: attr_from_assoc({:belongs_to, name, table}, namespace) + defp attr_from_assoc(_assoc, _opts), do: nil defp migration_attrs(attrs) do @@ -140,9 +159,11 @@ defmodule Mix.ExOauth2Provider.Migration do defp to_migration_attr({name, type}) do {name, type, ""} end + defp to_migration_attr({name, type, field_options}) do to_migration_attr({name, type, field_options, []}) end + defp to_migration_attr({name, type, field_options, migration_options}) do field_options |> Keyword.get(:default) @@ -155,7 +176,7 @@ defmodule Mix.ExOauth2Provider.Migration do to_migration_attr({name, type}) options -> - options = Enum.map_join(options, ", ", fn {k, v} -> "#{k}: #{inspect v}" end) + options = Enum.map_join(options, ", ", fn {k, v} -> "#{k}: #{inspect(v)}" end) {name, type, ", #{options}"} end @@ -174,7 +195,8 @@ defmodule Mix.ExOauth2Provider.Migration do _ -> false end) - attrs = Enum.map(attrs, fn {key_id, type, _defaults} -> {key_id, type} end) + attrs = Enum.map(attrs, fn {key_id, type, _defaults} -> {key_id, type} end) + assocs = Enum.map(assocs, fn {key_id, {:references, source}, _} -> key = String.replace(Atom.to_string(key_id), "_id", "") diff --git a/lib/mix/ex_oauth2_provider/schema.ex b/lib/mix/ex_oauth2_provider/schema.ex index ceced4d6..606ae58d 100644 --- a/lib/mix/ex_oauth2_provider/schema.ex +++ b/lib/mix/ex_oauth2_provider/schema.ex @@ -19,24 +19,44 @@ defmodule Mix.ExOauth2Provider.Schema do end """ - alias ExOauth2Provider.{AccessGrants.AccessGrant, AccessTokens.AccessToken, Applications.Application} + alias ExOauth2Provider.{ + AccessGrants.AccessGrant, + AccessTokens.AccessToken, + Applications.Application + } - @schemas [{"application", Application}, {"access_grant", AccessGrant}, {"access_token", AccessToken}] + @schemas [ + {"application", Application}, + {"access_grant", AccessGrant}, + {"access_token", AccessToken} + ] @spec create_schema_files(atom(), binary(), keyword()) :: any() def create_schema_files(context_app, namespace, opts) do for {table, schema} <- @schemas do - app_base = Config.app_base(context_app) - table_name = "#{namespace}_#{table}s" - context = Macro.camelize(table_name) - module = Macro.camelize("#{namespace}_#{table}") - file = "#{Macro.underscore(module)}.ex" - module = Module.concat([app_base, context, module]) - binary_id = Keyword.get(opts, :binary_id, false) - macro = schema + app_base = Config.app_base(context_app) + table_name = "#{namespace}_#{table}s" + context = Macro.camelize(table_name) + module = Macro.camelize("#{namespace}_#{table}") + file = "#{Macro.underscore(module)}.ex" + module = Module.concat([app_base, context, module]) + binary_id = Keyword.get(opts, :binary_id, false) + macro = schema macro_fields = "#{table}_fields" - content = EEx.eval_string(@template, schema: %{module: module, table: table_name, binary_id: binary_id, macro: macro, macro_fields: macro_fields}, otp_app: context_app) - dir = "lib/#{context_app}/#{Macro.underscore(context)}/" + + content = + EEx.eval_string(@template, + schema: %{ + module: module, + table: table_name, + binary_id: binary_id, + macro: macro, + macro_fields: macro_fields + }, + otp_app: context_app + ) + + dir = "lib/#{context_app}/#{Macro.underscore(context)}/" File.mkdir_p!(dir) diff --git a/lib/mix/tasks/ex_oauth2_provider.ex b/lib/mix/tasks/ex_oauth2_provider.ex index 9292509d..c0f8bf26 100644 --- a/lib/mix/tasks/ex_oauth2_provider.ex +++ b/lib/mix/tasks/ex_oauth2_provider.ex @@ -18,9 +18,9 @@ defmodule Mix.Tasks.ExOauth2Provider do defp general do Application.ensure_all_started(:ex_oauth2_provider) - Mix.shell.info "ExOauth2Provider v#{Application.spec(:ex_oauth2_provider, :vsn)}" - Mix.shell.info Application.spec(:ex_oauth2_provider, :description) - Mix.shell.info "\nAvailable tasks:\n" + Mix.shell().info("ExOauth2Provider v#{Application.spec(:ex_oauth2_provider, :vsn)}") + Mix.shell().info(Application.spec(:ex_oauth2_provider, :description)) + Mix.shell().info("\nAvailable tasks:\n") Mix.Tasks.Help.run(["--search", "ex_oauth2_provider."]) end end diff --git a/lib/mix/tasks/ex_oauth2_provider.gen.migration.ex b/lib/mix/tasks/ex_oauth2_provider.gen.migration.ex index c7658eec..e457fb63 100644 --- a/lib/mix/tasks/ex_oauth2_provider.gen.migration.ex +++ b/lib/mix/tasks/ex_oauth2_provider.gen.migration.ex @@ -28,9 +28,9 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.Migration do alias Mix.{Ecto, ExOauth2Provider, ExOauth2Provider.Migration} - @switches [binary_id: :boolean, namespace: :string] + @switches [binary_id: :boolean, namespace: :string] @default_opts [binary_id: false, namespace: "oauth"] - @mix_task "ex_oauth2_provider.gen.migrations" + @mix_task "ex_oauth2_provider.gen.migrations" @impl true def run(args) do @@ -53,8 +53,8 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.Migration do end defp create_migration_files(%{repo: repo, namespace: namespace} = config) do - name = "Create#{Macro.camelize(namespace)}Tables" - content = Migration.gen(name, namespace, config) + name = "Create#{Macro.camelize(namespace)}Tables" + content = Migration.gen(name, namespace, config) Migration.create_migration_file(repo, name, content) end diff --git a/lib/mix/tasks/ex_oauth2_provider.gen.schemas.ex b/lib/mix/tasks/ex_oauth2_provider.gen.schemas.ex index 4f6b263c..97dd0977 100644 --- a/lib/mix/tasks/ex_oauth2_provider.gen.schemas.ex +++ b/lib/mix/tasks/ex_oauth2_provider.gen.schemas.ex @@ -18,9 +18,9 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.Schemas do alias Mix.{ExOauth2Provider, ExOauth2Provider.Schema} - @switches [binary_id: :boolean, context_app: :string, namespace: :string] + @switches [binary_id: :boolean, context_app: :string, namespace: :string] @default_opts [binary_id: false, namespace: "oauth"] - @mix_task "ex_oauth2_provider.gen.migrations" + @mix_task "ex_oauth2_provider.gen.migrations" @impl true def run(args) do @@ -35,7 +35,7 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.Schemas do defp parse({config, _parsed, _invalid}), do: config defp create_schema_files(%{binary_id: binary_id, namespace: namespace} = config) do - context_app = Map.get(config, :context_app) || ExOauth2Provider.otp_app() + context_app = Map.get(config, :context_app) || ExOauth2Provider.otp_app() Schema.create_schema_files(context_app, namespace, binary_id: binary_id) end diff --git a/lib/mix/tasks/ex_oauth2_provider.install.ex b/lib/mix/tasks/ex_oauth2_provider.install.ex index b5e9c22d..103d8cbf 100644 --- a/lib/mix/tasks/ex_oauth2_provider.install.ex +++ b/lib/mix/tasks/ex_oauth2_provider.install.ex @@ -21,9 +21,9 @@ defmodule Mix.Tasks.ExOauth2Provider.Install do alias Mix.{Ecto, ExOauth2Provider, ExOauth2Provider.Config} alias Mix.Tasks.ExOauth2Provider.Gen.{Migration, Schemas} - @switches [context_app: :string, migration: :boolean, schemas: :boolean] + @switches [context_app: :string, migration: :boolean, schemas: :boolean] @default_opts [migration: true, schemas: true] - @mix_task "ex_oauth2_provider.install" + @mix_task "ex_oauth2_provider.install" @impl true def run(args) do @@ -44,6 +44,7 @@ defmodule Mix.Tasks.ExOauth2Provider.Install do config end + defp run_migration(config, _args), do: config defp run_schemas(%{schemas: true} = config, args) do @@ -51,24 +52,24 @@ defmodule Mix.Tasks.ExOauth2Provider.Install do config end + defp run_schemas(config, _args), do: config defp print_config_instructions(config, args) do [repo | _repos] = Ecto.parse_repo(args) - context_app = Map.get(config, :context_app) || ExOauth2Provider.otp_app() - resource_owner = resource_owner(ProviderConfig.app_base(context_app)) + context_app = Map.get(config, :context_app) || ExOauth2Provider.otp_app() + resource_owner = resource_owner(ProviderConfig.app_base(context_app)) content = Config.gen(context_app, repo: inspect(repo), resource_owner: resource_owner) - Mix.shell.info( - """ - ExOauth2Provider has been installed! Please append the following to `config/config.ex`: + Mix.shell().info(""" + ExOauth2Provider has been installed! Please append the following to `config/config.ex`: - #{content} - """) + #{content} + """) config end - defp resource_owner(base), do: inspect Module.concat([base, "Users", "User"]) + defp resource_owner(base), do: inspect(Module.concat([base, "Users", "User"])) end diff --git a/mix.exs b/mix.exs index 6b812d04..e478b520 100644 --- a/mix.exs +++ b/mix.exs @@ -7,9 +7,9 @@ defmodule ExOauth2Provider.Mixfile do [ app: :ex_oauth2_provider, version: @version, - elixir: "~> 1.12", - elixirc_paths: elixirc_paths(Mix.env), - start_permanent: Mix.env == :prod, + elixir: "~> 1.15", + elixirc_paths: elixirc_paths(Mix.env()), + start_permanent: Mix.env() == :prod, deps: deps(), # Hex @@ -34,18 +34,16 @@ defmodule ExOauth2Provider.Mixfile do defp deps do [ - {:ecto, "~> 3.10"}, - {:plug, ">= 1.5.0 and < 2.0.0"}, - {:jason, "~> 1.2"}, + {:ecto, "~> 3.11"}, + {:plug, ">= 1.15.0 and < 2.0.0"}, + {:jason, "~> 1.4"}, # Dev and test dependencies - {:credo, "~> 1.5", only: [:dev, :test]}, - - {:ex_doc, "~> 0.25", only: :dev}, - - {:ecto_sql, "~> 3.10", only: :test}, - {:plug_cowboy, "~> 2.0", only: :test}, - {:postgrex, "~> 0.14", only: :test} + {:credo, "~> 1.7", only: [:dev, :test]}, + {:ex_doc, "~> 0.31", only: :dev}, + {:ecto_sql, "~> 3.11", only: :test}, + {:plug_cowboy, "~> 2.6", only: :test}, + {:postgrex, "~> 0.17", only: :test} ] end diff --git a/mix.lock b/mix.lock index 9d7dfa25..1d9df9fb 100644 --- a/mix.lock +++ b/mix.lock @@ -1,27 +1,28 @@ %{ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"}, - "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e5580029080f3f1ad17436fb97b0d5ed2ed4e4815a96bac36b5a992e20f58db6"}, - "cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm", "1e1a3d176d52daebbecbbcdfd27c27726076567905c2a9d7398c54da9d225761"}, - "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"}, - "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, + "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, + "credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"}, + "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "earmark": {:hex, :earmark, "1.3.5", "0db71c8290b5bc81cb0101a2a507a76dca659513984d683119ee722828b424f6", [:mix], [], "hexpm", "762b999fd414fb41e297944228aa1de2cd4a3876a07f968c8b11d1e9a2190d07"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, - "ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"}, - "ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"}, - "ex_doc": {:hex, :ex_doc, "0.30.4", "e8395c8e3c007321abb30a334f9f7c0858d80949af298302daf77553468c0c39", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "9a19f0c50ffaa02435668f5242f2b2a61d46b541ebf326884505dfd3dd7af5e4"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, + "ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"}, + "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"}, + "ex_doc": {:hex, :ex_doc, "0.31.0", "06eb1dfd787445d9cab9a45088405593dd3bb7fe99e097eaa71f37ba80c7a676", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5350cafa6b7f77bdd107aa2199fe277acf29d739aba5aee7e865fc680c62a110"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, + "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, - "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, - "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm", "de9825f21c6fd6adfdeae8f9c80dcd88c1e58301f06bf13d659b7e606b88abe0"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "6cd8ddd1bd1fbfa54d3fc61d4719c2057dae67615395d58d40437a919a46f132"}, - "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm", "73c1682f0e414cfb5d9b95c8e8cd6ffcfdae699e3b05e1db744e58b7be857759"}, - "postgrex": {:hex, :postgrex, "0.17.2", "a3ec9e3239d9b33f1e5841565c4eb200055c52cc0757a22b63ca2d529bbe764c", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "80a918a9e9531d39f7bd70621422f3ebc93c01618c645f2d91306f50041ed90c"}, - "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"}, + "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "plug": {:hex, :plug, "1.15.2", "94cf1fa375526f30ff8770837cb804798e0045fd97185f0bb9e5fcd858c792a3", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02731fa0c2dcb03d8d21a1d941bdbbe99c2946c0db098eee31008e04c6283615"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, + "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, + "postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, } diff --git a/test/ex_oauth2_provider/access_grants/access_grants_test.exs b/test/ex_oauth2_provider/access_grants/access_grants_test.exs index 0e0b9098..e1989846 100644 --- a/test/ex_oauth2_provider/access_grants/access_grants_test.exs +++ b/test/ex_oauth2_provider/access_grants/access_grants_test.exs @@ -9,51 +9,75 @@ defmodule ExOauth2Provider.AccessGrantsTest do setup do user = Fixtures.resource_owner() - {:ok, %{user: user, application: Fixtures.application(resource_owner: user, scopes: "public read")}} + + {:ok, + %{user: user, application: Fixtures.application(resource_owner: user, scopes: "public read")}} end test "get_active_grant_for/3", %{user: user, application: application} do - {:ok, grant} = AccessGrants.create_grant(user, application, @valid_attrs, otp_app: :ex_oauth2_provider) + {:ok, grant} = + AccessGrants.create_grant(user, application, @valid_attrs, otp_app: :ex_oauth2_provider) + + assert %OauthAccessGrant{id: id} = + AccessGrants.get_active_grant_for(application, grant.token, + otp_app: :ex_oauth2_provider + ) - assert %OauthAccessGrant{id: id} = AccessGrants.get_active_grant_for(application, grant.token, otp_app: :ex_oauth2_provider) assert id == grant.id different_application = Fixtures.application(resource_owner: user, uid: "2") - refute AccessGrants.get_active_grant_for(different_application, grant.token, otp_app: :ex_oauth2_provider) + + refute AccessGrants.get_active_grant_for(different_application, grant.token, + otp_app: :ex_oauth2_provider + ) end describe "create_grant/4" do test "with valid attributes", %{user: user, application: application} do - assert {:ok, %OauthAccessGrant{} = grant} = AccessGrants.create_grant(user, application, @valid_attrs, otp_app: :ex_oauth2_provider) + assert {:ok, %OauthAccessGrant{} = grant} = + AccessGrants.create_grant(user, application, @valid_attrs, + otp_app: :ex_oauth2_provider + ) + assert grant.resource_owner == user assert grant.application == application assert grant.scopes == "public" end test "adds random token", %{user: user, application: application} do - {:ok, grant} = AccessGrants.create_grant(user, application, @valid_attrs, otp_app: :ex_oauth2_provider) - {:ok, grant2} = AccessGrants.create_grant(user, application, @valid_attrs, otp_app: :ex_oauth2_provider) + {:ok, grant} = + AccessGrants.create_grant(user, application, @valid_attrs, otp_app: :ex_oauth2_provider) + + {:ok, grant2} = + AccessGrants.create_grant(user, application, @valid_attrs, otp_app: :ex_oauth2_provider) + assert grant.token != grant2.token end test "with missing expires_in", %{application: application, user: user} do attrs = Map.merge(@valid_attrs, %{expires_in: nil}) - assert {:error, changeset} = AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert {:error, changeset} = + AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert changeset.errors[:expires_in] == {"can't be blank", [validation: :required]} end test "with missing redirect_uri", %{application: application, user: user} do attrs = Map.merge(@valid_attrs, %{redirect_uri: nil}) - assert {:error, changeset} = AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert {:error, changeset} = + AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert changeset.errors[:redirect_uri] == {"can't be blank", [validation: :required]} end test "with invalid scopes", %{application: application, user: user} do attrs = Map.merge(@valid_attrs, %{scopes: "write"}) - assert {:error, changeset} = AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert {:error, changeset} = + AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert changeset.errors[:scopes] == {"not in permitted scopes list: \"public read\"", []} end end @@ -67,14 +91,19 @@ defmodule ExOauth2Provider.AccessGrantsTest do test "with invalid scopes", %{application: application, user: user} do attrs = Map.merge(@valid_attrs, %{scopes: "invalid"}) - assert {:error, changeset} = AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) - assert changeset.errors[:scopes] == {"not in permitted scopes list: [\"public\", \"read\", \"write\"]", []} + assert {:error, changeset} = + AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + + assert changeset.errors[:scopes] == + {"not in permitted scopes list: [\"public\", \"read\", \"write\"]", []} end test "with valid attributes", %{application: application, user: user} do attrs = Map.merge(@valid_attrs, %{scopes: "write"}) - assert {:ok, grant} = AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert {:ok, grant} = + AccessGrants.create_grant(user, application, attrs, otp_app: :ex_oauth2_provider) + assert grant.scopes == "write" end end diff --git a/test/ex_oauth2_provider/access_tokens/access_tokens_test.exs b/test/ex_oauth2_provider/access_tokens/access_tokens_test.exs index 6ebe0c07..029fe533 100644 --- a/test/ex_oauth2_provider/access_tokens/access_tokens_test.exs +++ b/test/ex_oauth2_provider/access_tokens/access_tokens_test.exs @@ -11,50 +11,123 @@ defmodule ExOauth2Provider.AccessTokensTest do end test "get_by_token/2", %{user: user} do - assert {:ok, access_token} = AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) + assert {:ok, access_token} = + AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_by_token(access_token.token, otp_app: :ex_oauth2_provider) - assert %OauthAccessToken{id: id} = AccessTokens.get_by_token(access_token.token, otp_app: :ex_oauth2_provider) assert id == access_token.id end test "get_by_refresh_token/2", %{user: user} do - assert {:ok, access_token} = AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) + assert {:ok, access_token} = + AccessTokens.create_token(user, %{use_refresh_token: true}, + otp_app: :ex_oauth2_provider + ) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_by_refresh_token(access_token.refresh_token, + otp_app: :ex_oauth2_provider + ) - assert %OauthAccessToken{id: id} = AccessTokens.get_by_refresh_token(access_token.refresh_token, otp_app: :ex_oauth2_provider) assert id == access_token.id end describe "get_by_previous_refresh_token_for/3" do test "with resource owner", %{user: user} do - {:ok, old_access_token} = AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) - {:ok, new_access_token} = AccessTokens.create_token(user, %{use_refresh_token: true, previous_refresh_token: old_access_token}, otp_app: :ex_oauth2_provider) + {:ok, old_access_token} = + AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) + + {:ok, new_access_token} = + AccessTokens.create_token( + user, + %{use_refresh_token: true, previous_refresh_token: old_access_token}, + otp_app: :ex_oauth2_provider + ) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_by_previous_refresh_token_for(new_access_token, + otp_app: :ex_oauth2_provider + ) - assert %OauthAccessToken{id: id} = AccessTokens.get_by_previous_refresh_token_for(new_access_token, otp_app: :ex_oauth2_provider) assert id == old_access_token.id - refute AccessTokens.get_by_previous_refresh_token_for(old_access_token, otp_app: :ex_oauth2_provider) + refute AccessTokens.get_by_previous_refresh_token_for(old_access_token, + otp_app: :ex_oauth2_provider + ) - {:ok, new_access_token_different_user} = AccessTokens.create_token(Fixtures.resource_owner(), %{use_refresh_token: true, previous_refresh_token: old_access_token}, otp_app: :ex_oauth2_provider) + {:ok, new_access_token_different_user} = + AccessTokens.create_token( + Fixtures.resource_owner(), + %{use_refresh_token: true, previous_refresh_token: old_access_token}, + otp_app: :ex_oauth2_provider + ) - refute AccessTokens.get_by_previous_refresh_token_for(new_access_token_different_user, otp_app: :ex_oauth2_provider) + refute AccessTokens.get_by_previous_refresh_token_for(new_access_token_different_user, + otp_app: :ex_oauth2_provider + ) end test "with application", %{user: user, application: application} do - {:ok, old_access_token} = AccessTokens.create_token(user, %{application: application, use_refresh_token: true}, otp_app: :ex_oauth2_provider) - {:ok, new_access_token} = AccessTokens.create_token(user, %{application: application, use_refresh_token: true, previous_refresh_token: old_access_token}, otp_app: :ex_oauth2_provider) + {:ok, old_access_token} = + AccessTokens.create_token(user, %{application: application, use_refresh_token: true}, + otp_app: :ex_oauth2_provider + ) + + {:ok, new_access_token} = + AccessTokens.create_token( + user, + %{ + application: application, + use_refresh_token: true, + previous_refresh_token: old_access_token + }, + otp_app: :ex_oauth2_provider + ) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_by_previous_refresh_token_for(new_access_token, + otp_app: :ex_oauth2_provider + ) - assert %OauthAccessToken{id: id} = AccessTokens.get_by_previous_refresh_token_for(new_access_token, otp_app: :ex_oauth2_provider) assert id == old_access_token.id - refute AccessTokens.get_by_previous_refresh_token_for(old_access_token, otp_app: :ex_oauth2_provider) - - {:ok, new_access_token_different_user} = AccessTokens.create_token(Fixtures.resource_owner(), %{application: application, use_refresh_token: true, previous_refresh_token: old_access_token}, otp_app: :ex_oauth2_provider) - refute AccessTokens.get_by_previous_refresh_token_for(new_access_token_different_user, otp_app: :ex_oauth2_provider) + refute AccessTokens.get_by_previous_refresh_token_for(old_access_token, + otp_app: :ex_oauth2_provider + ) + + {:ok, new_access_token_different_user} = + AccessTokens.create_token( + Fixtures.resource_owner(), + %{ + application: application, + use_refresh_token: true, + previous_refresh_token: old_access_token + }, + otp_app: :ex_oauth2_provider + ) + + refute AccessTokens.get_by_previous_refresh_token_for(new_access_token_different_user, + otp_app: :ex_oauth2_provider + ) new_application = Fixtures.application(resource_owner: user, uid: "new_app") - {:ok, new_access_token_different_app} = AccessTokens.create_token(user, %{application: new_application, use_refresh_token: true, previous_refresh_token: old_access_token}, otp_app: :ex_oauth2_provider) - refute AccessTokens.get_by_previous_refresh_token_for(new_access_token_different_app, otp_app: :ex_oauth2_provider) + {:ok, new_access_token_different_app} = + AccessTokens.create_token( + user, + %{ + application: new_application, + use_refresh_token: true, + previous_refresh_token: old_access_token + }, + otp_app: :ex_oauth2_provider + ) + + refute AccessTokens.get_by_previous_refresh_token_for(new_access_token_different_app, + otp_app: :ex_oauth2_provider + ) end end @@ -64,33 +137,54 @@ defmodule ExOauth2Provider.AccessTokensTest do inserted_at = QueryHelpers.timestamp(OauthAccessToken, :inserted_at, seconds: -1) QueryHelpers.change!(access_token1, inserted_at: inserted_at) {:ok, access_token2} = AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) - {:ok, _access_token_with_application} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) - assert %OauthAccessToken{id: id} = AccessTokens.get_token_for(user, nil, nil, otp_app: :ex_oauth2_provider) + {:ok, _access_token_with_application} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_token_for(user, nil, nil, otp_app: :ex_oauth2_provider) + assert id == access_token2.id - refute AccessTokens.get_token_for(Fixtures.resource_owner(), nil, nil, otp_app: :ex_oauth2_provider) + refute AccessTokens.get_token_for(Fixtures.resource_owner(), nil, nil, + otp_app: :ex_oauth2_provider + ) end test "with application", %{user: user, application: application} do - {:ok, access_token1} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + {:ok, access_token1} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + inserted_at = QueryHelpers.timestamp(OauthAccessToken, :inserted_at, seconds: -1) QueryHelpers.change!(access_token1, inserted_at: inserted_at) - {:ok, access_token2} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) - {:ok, _access_token_without_application} = AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) - assert %OauthAccessToken{id: id} = AccessTokens.get_token_for(user, application, nil, otp_app: :ex_oauth2_provider) + {:ok, access_token2} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + + {:ok, _access_token_without_application} = + AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_token_for(user, application, nil, otp_app: :ex_oauth2_provider) + assert id == access_token2.id end test "with scopes", %{user: user} do - {:ok, access_token1} = AccessTokens.create_token(user, %{scopes: "public"}, otp_app: :ex_oauth2_provider) - {:ok, access_token2} = AccessTokens.create_token(user, %{scopes: "read write"}, otp_app: :ex_oauth2_provider) + {:ok, access_token1} = + AccessTokens.create_token(user, %{scopes: "public"}, otp_app: :ex_oauth2_provider) + + {:ok, access_token2} = + AccessTokens.create_token(user, %{scopes: "read write"}, otp_app: :ex_oauth2_provider) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_token_for(user, nil, "public", otp_app: :ex_oauth2_provider) - assert %OauthAccessToken{id: id} = AccessTokens.get_token_for(user, nil, "public", otp_app: :ex_oauth2_provider) assert id == access_token1.id - assert %OauthAccessToken{id: id} = AccessTokens.get_token_for(user, nil, "write read", otp_app: :ex_oauth2_provider) + assert %OauthAccessToken{id: id} = + AccessTokens.get_token_for(user, nil, "write read", otp_app: :ex_oauth2_provider) + assert id == access_token2.id refute AccessTokens.get_token_for(user, nil, "other_read", otp_app: :ex_oauth2_provider) @@ -109,7 +203,11 @@ defmodule ExOauth2Provider.AccessTokensTest do assert AccessTokens.get_token_for(user, nil, nil, otp_app: :ex_oauth2_provider) - inserted_at = QueryHelpers.timestamp(access_token.__struct__, :inserted_at, seconds: -access_token.expires_in) + inserted_at = + QueryHelpers.timestamp(access_token.__struct__, :inserted_at, + seconds: -access_token.expires_in + ) + QueryHelpers.change!(access_token, inserted_at: inserted_at) refute AccessTokens.get_token_for(user, nil, nil, otp_app: :ex_oauth2_provider) @@ -118,44 +216,67 @@ defmodule ExOauth2Provider.AccessTokensTest do describe "get_application_token_for/3" do test "fetches", %{application: application} do - {:ok, access_token1} = AccessTokens.create_application_token(application, %{}, otp_app: :ex_oauth2_provider) + {:ok, access_token1} = + AccessTokens.create_application_token(application, %{}, otp_app: :ex_oauth2_provider) + inserted_at = QueryHelpers.timestamp(OauthAccessToken, :inserted_at, seconds: -1) QueryHelpers.change!(access_token1, inserted_at: inserted_at) - {:ok, access_token2} = AccessTokens.create_application_token(application, %{}, otp_app: :ex_oauth2_provider) - assert %OauthAccessToken{id: id} = AccessTokens.get_application_token_for(application, nil, otp_app: :ex_oauth2_provider) + {:ok, access_token2} = + AccessTokens.create_application_token(application, %{}, otp_app: :ex_oauth2_provider) + + assert %OauthAccessToken{id: id} = + AccessTokens.get_application_token_for(application, nil, + otp_app: :ex_oauth2_provider + ) + assert id == access_token2.id - refute AccessTokens.get_application_token_for(Fixtures.application(uid: "application-2"), nil, otp_app: :ex_oauth2_provider) + refute AccessTokens.get_application_token_for( + Fixtures.application(uid: "application-2"), + nil, + otp_app: :ex_oauth2_provider + ) end end test "get_authorized_tokens_for/2", %{user: user, application: application} do - {:ok, access_token} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + {:ok, access_token} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + + assert [%OauthAccessToken{id: id}] = + AccessTokens.get_authorized_tokens_for(user, otp_app: :ex_oauth2_provider) - assert [%OauthAccessToken{id: id}] = AccessTokens.get_authorized_tokens_for(user, otp_app: :ex_oauth2_provider) assert id == access_token.id QueryHelpers.change!(access_token, expires_in: -1) - assert [%OauthAccessToken{id: id}] = AccessTokens.get_authorized_tokens_for(user, otp_app: :ex_oauth2_provider) + assert [%OauthAccessToken{id: id}] = + AccessTokens.get_authorized_tokens_for(user, otp_app: :ex_oauth2_provider) + assert id == access_token.id AccessTokens.revoke(access_token, otp_app: :ex_oauth2_provider) assert AccessTokens.get_authorized_tokens_for(user, otp_app: :ex_oauth2_provider) == [] - assert AccessTokens.get_authorized_tokens_for(Fixtures.resource_owner(), otp_app: :ex_oauth2_provider) == [] + assert AccessTokens.get_authorized_tokens_for(Fixtures.resource_owner(), + otp_app: :ex_oauth2_provider + ) == [] end describe "create_token/3" do test "with valid attributes", %{user: user} do - assert {:ok, access_token} = AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) + assert {:ok, access_token} = + AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) + assert access_token.resource_owner_id == user.id assert is_nil(access_token.application_id) end test "with resource owner and application", %{user: user, application: application} do - {:ok, access_token} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + {:ok, access_token} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + assert access_token.resource_owner_id == user.id assert access_token.application_id == application.id end @@ -167,70 +288,112 @@ defmodule ExOauth2Provider.AccessTokensTest do end test "with custom access token generator", %{user: user} do - {:ok, access_token} = AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider, access_token_generator: {__MODULE__, :access_token_generator}) + {:ok, access_token} = + AccessTokens.create_token(user, %{}, + otp_app: :ex_oauth2_provider, + access_token_generator: {__MODULE__, :access_token_generator} + ) + assert access_token.token == "custom_generated-#{user.id}" end test "adds previous_refresh_token", %{user: user} do - {:ok, old_access_token} = AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) - {:ok, new_access_token} = AccessTokens.create_token(user, %{use_refresh_token: true, previous_refresh_token: old_access_token}, otp_app: :ex_oauth2_provider) + {:ok, old_access_token} = + AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) + + {:ok, new_access_token} = + AccessTokens.create_token( + user, + %{use_refresh_token: true, previous_refresh_token: old_access_token}, + otp_app: :ex_oauth2_provider + ) + assert new_access_token.previous_refresh_token == old_access_token.refresh_token end test "adds random refresh token", %{user: user} do - {:ok, access_token} = AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) - {:ok, access_token2} = AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) + {:ok, access_token} = + AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) + + {:ok, access_token2} = + AccessTokens.create_token(user, %{use_refresh_token: true}, otp_app: :ex_oauth2_provider) + assert access_token.refresh_token != access_token2.refresh_token end test "doesn't add refresh token when disabled", %{user: user} do - {:ok, access_token} = AccessTokens.create_token(user, %{use_refresh_token: false}, otp_app: :ex_oauth2_provider) + {:ok, access_token} = + AccessTokens.create_token(user, %{use_refresh_token: false}, otp_app: :ex_oauth2_provider) + assert is_nil(access_token.refresh_token) end test "with no scopes", %{user: user} do - assert {:ok, access_token} = AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) + assert {:ok, access_token} = + AccessTokens.create_token(user, %{}, otp_app: :ex_oauth2_provider) + assert access_token.scopes == "public" end test "with custom scopes", %{user: user} do - assert {:ok, access_token} = AccessTokens.create_token(user, %{scopes: "read"}, otp_app: :ex_oauth2_provider) + assert {:ok, access_token} = + AccessTokens.create_token(user, %{scopes: "read"}, otp_app: :ex_oauth2_provider) + assert access_token.scopes == "read" end test "with invalid scopes", %{user: user} do - assert {:error, changeset} = AccessTokens.create_token(user, %{scopes: "invalid"}, otp_app: :ex_oauth2_provider) - assert changeset.errors[:scopes] == {"not in permitted scopes list: [\"public\", \"read\", \"write\"]", []} + assert {:error, changeset} = + AccessTokens.create_token(user, %{scopes: "invalid"}, otp_app: :ex_oauth2_provider) + + assert changeset.errors[:scopes] == + {"not in permitted scopes list: [\"public\", \"read\", \"write\"]", []} end end describe "create_token/3 with application scopes" do setup %{user: user, application: application} do - application = Map.merge(application, %{scopes: "public app:write app:read"}) + application = Map.merge(application, %{scopes: "public app:write app:read"}) - %{user: user, application: application} + %{user: user, application: application} end test "with no scopes", %{user: user, application: application} do - assert {:ok, access_token} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + assert {:ok, access_token} = + AccessTokens.create_token(user, %{application: application}, + otp_app: :ex_oauth2_provider + ) + assert access_token.scopes == "public" end test "with custom scopes", %{user: user, application: application} do application = Map.merge(application, %{scopes: "app:read"}) - assert {:ok, access_token} = AccessTokens.create_token(user, %{scopes: "app:read", application: application}, otp_app: :ex_oauth2_provider) + + assert {:ok, access_token} = + AccessTokens.create_token(user, %{scopes: "app:read", application: application}, + otp_app: :ex_oauth2_provider + ) + assert access_token.scopes == "app:read" end test "with invalid scopes", %{user: user, application: application} do application = Map.merge(application, %{scopes: "app:read"}) - assert {:error, changeset} = AccessTokens.create_token(user, %{application: application, scopes: "app:write"}, otp_app: :ex_oauth2_provider) + + assert {:error, changeset} = + AccessTokens.create_token(user, %{application: application, scopes: "app:write"}, + otp_app: :ex_oauth2_provider + ) + assert changeset.errors[:scopes] == {"not in permitted scopes list: \"app:read\"", []} end end test "create_application_token/3", %{application: application} do - {:ok, access_token} = AccessTokens.create_application_token(application, %{}, otp_app: :ex_oauth2_provider) + {:ok, access_token} = + AccessTokens.create_application_token(application, %{}, otp_app: :ex_oauth2_provider) + assert is_nil(access_token.resource_owner_id) assert access_token.application_id == application.id end @@ -254,23 +417,41 @@ defmodule ExOauth2Provider.AccessTokensTest do end test "is_revoked?/1" do - assert AccessTokens.is_revoked?(%OauthAccessToken{revoked_at: QueryHelpers.timestamp(OauthAccessToken, :revoked_at)}) + assert AccessTokens.is_revoked?(%OauthAccessToken{ + revoked_at: QueryHelpers.timestamp(OauthAccessToken, :revoked_at) + }) + refute AccessTokens.is_revoked?(%OauthAccessToken{revoked_at: nil}) end describe "is_accessible?/1" do test "with active" do - access_token = %OauthAccessToken{expires_in: 1, revoked_at: nil, inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at)} + access_token = %OauthAccessToken{ + expires_in: 1, + revoked_at: nil, + inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at) + } + assert AccessTokens.is_accessible?(access_token) end test "when revoked" do - access_token = %OauthAccessToken{expires_in: 1, revoked_at: QueryHelpers.timestamp(OauthAccessToken, :revoked_at), inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at)} + access_token = %OauthAccessToken{ + expires_in: 1, + revoked_at: QueryHelpers.timestamp(OauthAccessToken, :revoked_at), + inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at) + } + refute AccessTokens.is_accessible?(access_token) end test "when expired" do - access_token = %OauthAccessToken{expires_in: 0, revoked_at: nil, inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at)} + access_token = %OauthAccessToken{ + expires_in: 0, + revoked_at: nil, + inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at) + } + refute AccessTokens.is_accessible?(access_token) inserted_at = QueryHelpers.timestamp(OauthAccessToken, :inserted_at, seconds: -2) @@ -279,7 +460,12 @@ defmodule ExOauth2Provider.AccessTokensTest do end test "when never expires" do - access_token = %OauthAccessToken{expires_in: nil, revoked_at: nil, inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at)} + access_token = %OauthAccessToken{ + expires_in: nil, + revoked_at: nil, + inserted_at: QueryHelpers.timestamp(OauthAccessToken, :inserted_at) + } + assert AccessTokens.is_accessible?(access_token) end diff --git a/test/ex_oauth2_provider/applications/application_test.exs b/test/ex_oauth2_provider/applications/application_test.exs index 07d7d24d..5c443906 100644 --- a/test/ex_oauth2_provider/applications/application_test.exs +++ b/test/ex_oauth2_provider/applications/application_test.exs @@ -35,11 +35,8 @@ defmodule ExOauth2Provider.Applications.ApplicationTest do end test "require valid redirect uri", %{application: application} do - ["", - "invalid", - "https://example.com invalid", - "https://example.com http://example.com"] - |> Enum.each(fn(redirect_uri) -> + ["", "invalid", "https://example.com invalid", "https://example.com http://example.com"] + |> Enum.each(fn redirect_uri -> changeset = Application.changeset(application, %{redirect_uri: redirect_uri}) assert changeset.errors[:redirect_uri] end) @@ -63,7 +60,7 @@ defmodule ExOauth2Provider.Applications.ApplicationTest do end schema "oauth_applications" do - belongs_to :owner, __MODULE__ + belongs_to(:owner, __MODULE__) application_fields() timestamps() @@ -71,6 +68,7 @@ defmodule ExOauth2Provider.Applications.ApplicationTest do end test "with overridden `:owner`" do - assert %Ecto.Association.BelongsTo{owner: OverrideOwner} = OverrideOwner.__schema__(:association, :owner) + assert %Ecto.Association.BelongsTo{owner: OverrideOwner} = + OverrideOwner.__schema__(:association, :owner) end end diff --git a/test/ex_oauth2_provider/applications/applications_test.exs b/test/ex_oauth2_provider/applications/applications_test.exs index 2faaeb82..1706cf6e 100644 --- a/test/ex_oauth2_provider/applications/applications_test.exs +++ b/test/ex_oauth2_provider/applications/applications_test.exs @@ -5,87 +5,134 @@ defmodule ExOauth2Provider.ApplicationsTest do alias ExOauth2Provider.{AccessTokens, Applications} alias Dummy.{OauthApplications.OauthApplication, OauthAccessTokens.OauthAccessToken, Repo} - @valid_attrs %{name: "Application", redirect_uri: "https://example.org/endpoint"} - @invalid_attrs %{} + @valid_attrs %{name: "Application", redirect_uri: "https://example.org/endpoint"} + @invalid_attrs %{} setup do {:ok, %{user: Fixtures.resource_owner()}} end test "get_applications_for/2", %{user: user} do - assert {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) - assert {:ok, _application} = Applications.create_application(Fixtures.resource_owner(), @valid_attrs, otp_app: :ex_oauth2_provider) + assert {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + assert {:ok, _application} = + Applications.create_application(Fixtures.resource_owner(), @valid_attrs, + otp_app: :ex_oauth2_provider + ) + + assert [%OauthApplication{id: id}] = + Applications.get_applications_for(user, otp_app: :ex_oauth2_provider) - assert [%OauthApplication{id: id}] = Applications.get_applications_for(user, otp_app: :ex_oauth2_provider) assert id == application.id end test "get_application!/2", %{user: user} do - assert {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + assert {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + assert %OauthApplication{id: id} = + Applications.get_application!(application.uid, otp_app: :ex_oauth2_provider) - assert %OauthApplication{id: id} = Applications.get_application!(application.uid, otp_app: :ex_oauth2_provider) assert id == application.id end test "get_application/2", %{user: user} do - assert {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + assert {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + assert %OauthApplication{id: id} = + Applications.get_application(application.uid, otp_app: :ex_oauth2_provider) - assert %OauthApplication{id: id} = Applications.get_application(application.uid, otp_app: :ex_oauth2_provider) assert id == application.id end test "get_application_for!/2", %{user: user} do - {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + assert %OauthApplication{id: id} = + Applications.get_application_for!(user, application.uid, + otp_app: :ex_oauth2_provider + ) - assert %OauthApplication{id: id} = Applications.get_application_for!(user, application.uid, otp_app: :ex_oauth2_provider) assert id == application.id assert_raise Ecto.NoResultsError, fn -> - Applications.get_application_for!(Fixtures.resource_owner(), application.uid, otp_app: :ex_oauth2_provider) + Applications.get_application_for!(Fixtures.resource_owner(), application.uid, + otp_app: :ex_oauth2_provider + ) end end test "get_authorized_applications_for/2", %{user: user} do application = Fixtures.application() application2 = Fixtures.application(uid: "newapp") - assert {:ok, token} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) - assert {:ok, _token} = AccessTokens.create_token(user, %{application: application2}, otp_app: :ex_oauth2_provider) - assert Applications.get_authorized_applications_for(user, otp_app: :ex_oauth2_provider) == [application, application2] - assert Applications.get_authorized_applications_for(Fixtures.resource_owner(), otp_app: :ex_oauth2_provider) == [] + assert {:ok, token} = + AccessTokens.create_token(user, %{application: application}, + otp_app: :ex_oauth2_provider + ) + + assert {:ok, _token} = + AccessTokens.create_token(user, %{application: application2}, + otp_app: :ex_oauth2_provider + ) + + assert Applications.get_authorized_applications_for(user, otp_app: :ex_oauth2_provider) == [ + application, + application2 + ] + + assert Applications.get_authorized_applications_for(Fixtures.resource_owner(), + otp_app: :ex_oauth2_provider + ) == [] AccessTokens.revoke(token, otp_app: :ex_oauth2_provider) - assert Applications.get_authorized_applications_for(user, otp_app: :ex_oauth2_provider) == [application2] + + assert Applications.get_authorized_applications_for(user, otp_app: :ex_oauth2_provider) == [ + application2 + ] end describe "create_application/3" do test "with valid attributes", %{user: user} do - assert {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + assert {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + assert application.name == @valid_attrs.name assert application.scopes == "public" end test "with invalid attributes", %{user: user} do - assert {:error, changeset} = Applications.create_application(user, @invalid_attrs, otp_app: :ex_oauth2_provider) + assert {:error, changeset} = + Applications.create_application(user, @invalid_attrs, otp_app: :ex_oauth2_provider) + assert changeset.errors[:name] end test "with invalid scopes", %{user: user} do attrs = Map.merge(@valid_attrs, %{scopes: "invalid"}) - assert {:error, %Ecto.Changeset{}} = Applications.create_application(user, attrs, otp_app: :ex_oauth2_provider) + assert {:error, %Ecto.Changeset{}} = + Applications.create_application(user, attrs, otp_app: :ex_oauth2_provider) end test "with limited scopes", %{user: user} do attrs = Map.merge(@valid_attrs, %{scopes: "read write"}) - assert {:ok, application} = Applications.create_application(user, attrs, otp_app: :ex_oauth2_provider) + assert {:ok, application} = + Applications.create_application(user, attrs, otp_app: :ex_oauth2_provider) + assert application.scopes == "read write" end test "adds random secret", %{user: user} do - {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) - {:ok, application2} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + {:ok, application2} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) assert application.secret != application2.secret end @@ -93,38 +140,60 @@ defmodule ExOauth2Provider.ApplicationsTest do test "permits empty string secret", %{user: user} do attrs = Map.merge(@valid_attrs, %{secret: ""}) - assert {:ok, application} = Applications.create_application(user, attrs, otp_app: :ex_oauth2_provider) + assert {:ok, application} = + Applications.create_application(user, attrs, otp_app: :ex_oauth2_provider) + assert application.secret == "" end test "adds random uid", %{user: user} do - {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) - {:ok, application2} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + {:ok, application2} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + assert application.uid != application2.uid end test "adds custom uid", %{user: user} do - {:ok, application} = Applications.create_application(user, Map.merge(@valid_attrs, %{uid: "custom"}), otp_app: :ex_oauth2_provider) + {:ok, application} = + Applications.create_application(user, Map.merge(@valid_attrs, %{uid: "custom"}), + otp_app: :ex_oauth2_provider + ) + assert application.uid == "custom" end test "adds custom secret", %{user: user} do - {:ok, application} = Applications.create_application(user, Map.merge(@valid_attrs, %{secret: "custom"}), otp_app: :ex_oauth2_provider) + {:ok, application} = + Applications.create_application(user, Map.merge(@valid_attrs, %{secret: "custom"}), + otp_app: :ex_oauth2_provider + ) + assert application.secret == "custom" end end test "update_application/3", %{user: user} do - assert {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + assert {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + assert {:ok, application} = + Applications.update_application(application, %{name: "Updated App"}, + otp_app: :ex_oauth2_provider + ) - assert {:ok, application} = Applications.update_application(application, %{name: "Updated App"}, otp_app: :ex_oauth2_provider) assert application.name == "Updated App" end test "delete_application/2", %{user: user} do - {:ok, application} = Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + {:ok, application} = + Applications.create_application(user, @valid_attrs, otp_app: :ex_oauth2_provider) + + assert {:ok, _appliction} = + Applications.delete_application(application, otp_app: :ex_oauth2_provider) - assert {:ok, _appliction} = Applications.delete_application(application, otp_app: :ex_oauth2_provider) assert_raise Ecto.NoResultsError, fn -> Applications.get_application!(application.uid, otp_app: :ex_oauth2_provider) end @@ -132,12 +201,23 @@ defmodule ExOauth2Provider.ApplicationsTest do test "revoke_all_access_tokens_for/3", %{user: user} do application = Fixtures.application() - {:ok, token} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) - {:ok, token2} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) - {:ok, token3} = AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + + {:ok, token} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + + {:ok, token2} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + + {:ok, token3} = + AccessTokens.create_token(user, %{application: application}, otp_app: :ex_oauth2_provider) + AccessTokens.revoke(token3) - assert {:ok, objects} = Applications.revoke_all_access_tokens_for(application, user, otp_app: :ex_oauth2_provider) + assert {:ok, objects} = + Applications.revoke_all_access_tokens_for(application, user, + otp_app: :ex_oauth2_provider + ) + assert Enum.count(objects) == 2 assert AccessTokens.is_revoked?(Repo.get!(OauthAccessToken, token.id)) diff --git a/test/ex_oauth2_provider/oauth2/authorization/strategy/code_test.exs b/test/ex_oauth2_provider/oauth2/authorization/strategy/code_test.exs index ca6d2d23..50014309 100644 --- a/test/ex_oauth2_provider/oauth2/authorization/strategy/code_test.exs +++ b/test/ex_oauth2_provider/oauth2/authorization/strategy/code_test.exs @@ -5,23 +5,34 @@ defmodule ExOauth2Provider.Authorization.CodeTest do alias ExOauth2Provider.Test.{Fixtures, QueryHelpers} alias Dummy.{OauthAccessGrants.OauthAccessGrant, Repo} - @client_id "Jf5rM8hQBc" - @valid_request %{"client_id" => @client_id, "response_type" => "code", "scope" => "app:read app:write"} - @invalid_request %{error: :invalid_request, - error_description: "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." - } - @invalid_client %{error: :invalid_client, - error_description: "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." - } - @invalid_scope %{error: :invalid_scope, - error_description: "The requested scope is invalid, unknown, or malformed." - } - @invalid_redirect_uri %{error: :invalid_redirect_uri, - error_description: "The redirect uri included is not valid." - } - @access_denied %{error: :access_denied, - error_description: "The resource owner or authorization server denied the request." - } + @client_id "Jf5rM8hQBc" + @valid_request %{ + "client_id" => @client_id, + "response_type" => "code", + "scope" => "app:read app:write" + } + @invalid_request %{ + error: :invalid_request, + error_description: + "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." + } + @invalid_client %{ + error: :invalid_client, + error_description: + "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + } + @invalid_scope %{ + error: :invalid_scope, + error_description: "The requested scope is invalid, unknown, or malformed." + } + @invalid_redirect_uri %{ + error: :invalid_redirect_uri, + error_description: "The redirect uri included is not valid." + } + @access_denied %{ + error: :access_denied, + error_description: "The resource owner or authorization server denied the request." + } setup do resource_owner = Fixtures.resource_owner() @@ -30,50 +41,72 @@ defmodule ExOauth2Provider.Authorization.CodeTest do end test "#preauthorize/3 error when no resource owner" do - assert Authorization.preauthorize(nil, @valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.preauthorize(nil, @valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#preauthorize/3 error when no client_id", %{resource_owner: resource_owner} do request = Map.delete(@valid_request, "client_id") - assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#preauthorize/3 error when invalid client", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"client_id" => "invalid"}) - assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_client, :unprocessable_entity} + assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client, :unprocessable_entity} end test "#preauthorize/3", %{resource_owner: resource_owner, application: application} do expected_scopes = Scopes.to_list(@valid_request["scope"]) - assert Authorization.preauthorize(resource_owner, @valid_request, otp_app: :ex_oauth2_provider) == {:ok, application, expected_scopes} + assert Authorization.preauthorize(resource_owner, @valid_request, + otp_app: :ex_oauth2_provider + ) == {:ok, application, expected_scopes} end - test "#preauthorize/3 when previous access token with different application scopes", %{resource_owner: resource_owner, application: application} do - access_token = Fixtures.access_token(resource_owner: resource_owner, application: application, scopes: "app:read") + test "#preauthorize/3 when previous access token with different application scopes", %{ + resource_owner: resource_owner, + application: application + } do + access_token = + Fixtures.access_token( + resource_owner: resource_owner, + application: application, + scopes: "app:read" + ) + expected_scopes = Scopes.to_list(@valid_request["scope"]) - assert Authorization.preauthorize(resource_owner, @valid_request, otp_app: :ex_oauth2_provider) == {:ok, application, expected_scopes} + assert Authorization.preauthorize(resource_owner, @valid_request, + otp_app: :ex_oauth2_provider + ) == {:ok, application, expected_scopes} QueryHelpers.change!(access_token, scopes: "app:read app:write") request = Map.merge(@valid_request, %{"scope" => "app:read"}) expected_scopes = Scopes.to_list(request["scope"]) - assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:ok, application, expected_scopes} + assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:ok, application, expected_scopes} end - test "#preauthorize/3 with limited scope", %{resource_owner: resource_owner, application: application} do + test "#preauthorize/3 with limited scope", %{ + resource_owner: resource_owner, + application: application + } do request = Map.merge(@valid_request, %{"scope" => "app:read"}) - assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:ok, application, ["app:read"]} + assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:ok, application, ["app:read"]} end test "#preauthorize/3 error when invalid scope", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"scope" => "app:invalid"}) - assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_scope, :unprocessable_entity} + assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_scope, :unprocessable_entity} end describe "#preauthorize/3 when application has no scope" do @@ -86,45 +119,62 @@ defmodule ExOauth2Provider.Authorization.CodeTest do test "with limited server scope", %{resource_owner: resource_owner, application: application} do request = Map.merge(@valid_request, %{"scope" => "read"}) - assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:ok, application, ["read"]} + assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:ok, application, ["read"]} end test "error when invalid server scope", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"scope" => "invalid"}) - assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_scope, :unprocessable_entity} + assert Authorization.preauthorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_scope, :unprocessable_entity} end end - test "#preauthorize/3 when previous access token with same scopes", %{resource_owner: resource_owner, application: application} do - Fixtures.access_token(resource_owner: resource_owner, application: application, scopes: @valid_request["scope"]) + test "#preauthorize/3 when previous access token with same scopes", %{ + resource_owner: resource_owner, + application: application + } do + Fixtures.access_token( + resource_owner: resource_owner, + application: application, + scopes: @valid_request["scope"] + ) + + assert {:native_redirect, %{code: code}} = + Authorization.preauthorize(resource_owner, @valid_request, + otp_app: :ex_oauth2_provider + ) - assert {:native_redirect, %{code: code}} = Authorization.preauthorize(resource_owner, @valid_request, otp_app: :ex_oauth2_provider) access_grant = QueryHelpers.get_latest_inserted(OauthAccessGrant) assert code == access_grant.token end test "#authorize/3 rejects when no resource owner" do - assert Authorization.authorize(nil, @valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.authorize(nil, @valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#authorize/3 error when invalid client", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"client_id" => "invalid"}) - assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_client, :unprocessable_entity} + assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client, :unprocessable_entity} end test "#authorize/3 error when no client_id", %{resource_owner: resource_owner} do request = Map.delete(@valid_request, "client_id") - assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#authorize/3 error when invalid scope", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"scope" => "app:read app:profile"}) - assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_scope, :unprocessable_entity} + assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_scope, :unprocessable_entity} end describe "#authorize/3 when application has no scope" do @@ -136,12 +186,16 @@ defmodule ExOauth2Provider.Authorization.CodeTest do test "error when invalid server scope", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"scope" => "public profile"}) - assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_scope, :unprocessable_entity} + + assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_scope, :unprocessable_entity} end test "generates grant", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"scope" => "public"}) - assert {:native_redirect, %{code: code}} = Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) + + assert {:native_redirect, %{code: code}} = + Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) access_grant = Repo.get_by(OauthAccessGrant, token: code) assert access_grant.resource_owner_id == resource_owner.id @@ -151,53 +205,84 @@ defmodule ExOauth2Provider.Authorization.CodeTest do test "#authorize/3 error when invalid redirect uri", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"redirect_uri" => "/invalid/path"}) - assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_redirect_uri, :unprocessable_entity} + assert Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_redirect_uri, :unprocessable_entity} end test "#authorize/3 generates grant", %{resource_owner: resource_owner} do - assert {:native_redirect, %{code: code}} = Authorization.authorize(resource_owner, @valid_request, otp_app: :ex_oauth2_provider) + assert {:native_redirect, %{code: code}} = + Authorization.authorize(resource_owner, @valid_request, otp_app: :ex_oauth2_provider) + access_grant = Repo.get_by(OauthAccessGrant, token: code) assert access_grant.resource_owner_id == resource_owner.id - assert access_grant.expires_in == Config.authorization_code_expires_in(otp_app: :ex_oauth2_provider) + + assert access_grant.expires_in == + Config.authorization_code_expires_in(otp_app: :ex_oauth2_provider) + assert access_grant.scopes == @valid_request["scope"] end - test "#authorize/3 generates grant with redirect uri", %{resource_owner: resource_owner, application: application} do - QueryHelpers.change!(application, redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path") + test "#authorize/3 generates grant with redirect uri", %{ + resource_owner: resource_owner, + application: application + } do + QueryHelpers.change!(application, + redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path" + ) - request = Map.merge(@valid_request, %{"redirect_uri" => "https://example.com/path?param=1", "state" => 40_612}) + request = + Map.merge(@valid_request, %{ + "redirect_uri" => "https://example.com/path?param=1", + "state" => 40_612 + }) + + assert {:redirect, redirect_uri} = + Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) - assert {:redirect, redirect_uri} = Authorization.authorize(resource_owner, request, otp_app: :ex_oauth2_provider) access_grant = QueryHelpers.get_latest_inserted(OauthAccessGrant) - assert redirect_uri == "https://example.com/path?code=#{access_grant.token}¶m=1&state=40612" + assert redirect_uri == + "https://example.com/path?code=#{access_grant.token}¶m=1&state=40612" end test "#deny/3 error when no resource owner" do - assert Authorization.deny(nil, @valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.deny(nil, @valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#deny/3 error when invalid client", %{resource_owner: resource_owner} do request = Map.merge(@valid_request, %{"client_id" => "invalid"}) - assert Authorization.deny(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_client, :unprocessable_entity} + assert Authorization.deny(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client, :unprocessable_entity} end test "#deny/3 error when no client_id", %{resource_owner: resource_owner} do request = Map.delete(@valid_request, "client_id") - assert Authorization.deny(resource_owner, request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.deny(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#deny/3", %{resource_owner: resource_owner} do - assert Authorization.deny(resource_owner, @valid_request, otp_app: :ex_oauth2_provider) == {:error, @access_denied, :unauthorized} + assert Authorization.deny(resource_owner, @valid_request, otp_app: :ex_oauth2_provider) == + {:error, @access_denied, :unauthorized} end test "#deny/3 with redirection uri", %{application: application, resource_owner: resource_owner} do - QueryHelpers.change!(application, redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path") - request = Map.merge(@valid_request, %{"redirect_uri" => "https://example.com/path?param=1", "state" => 40_612}) - - assert Authorization.deny(resource_owner, request, otp_app: :ex_oauth2_provider) == {:redirect, "https://example.com/path?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.¶m=1&state=40612"} + QueryHelpers.change!(application, + redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path" + ) + + request = + Map.merge(@valid_request, %{ + "redirect_uri" => "https://example.com/path?param=1", + "state" => 40_612 + }) + + assert Authorization.deny(resource_owner, request, otp_app: :ex_oauth2_provider) == + {:redirect, + "https://example.com/path?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.¶m=1&state=40612"} end end diff --git a/test/ex_oauth2_provider/oauth2/authorization_test.exs b/test/ex_oauth2_provider/oauth2/authorization_test.exs index e6074033..7a960875 100644 --- a/test/ex_oauth2_provider/oauth2/authorization_test.exs +++ b/test/ex_oauth2_provider/oauth2/authorization_test.exs @@ -4,75 +4,107 @@ defmodule ExOauth2Provider.AuthorizationTest do alias ExOauth2Provider.Authorization alias ExOauth2Provider.Test.{Fixtures, QueryHelpers} - @client_id "Jf5rM8hQBc" - @client_secret "secret" - @valid_request %{"client_id" => @client_id, "response_type" => "code", "scope" => "app:read app:write"} - @invalid_request %{error: :invalid_request, - error_description: "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." - } - @invalid_response_type %{error: :unsupported_response_type, - error_description: "The authorization server does not support this response type." - } + @client_id "Jf5rM8hQBc" + @client_secret "secret" + @valid_request %{ + "client_id" => @client_id, + "response_type" => "code", + "scope" => "app:read app:write" + } + @invalid_request %{ + error: :invalid_request, + error_description: + "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." + } + @invalid_response_type %{ + error: :unsupported_response_type, + error_description: "The authorization server does not support this response type." + } setup do user = Fixtures.resource_owner() - application = Fixtures.application(resource_owner: user, uid: @client_id, secret: @client_secret) + + application = + Fixtures.application(resource_owner: user, uid: @client_id, secret: @client_secret) + {:ok, %{resource_owner: user, application: application}} end test "#preauthorize/3 error when missing response_type", %{resource_owner: resource_owner} do params = Map.delete(@valid_request, "response_type") - assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end - test "#preauthorize/3 redirect when missing response_type", %{resource_owner: resource_owner, application: application} do - QueryHelpers.change!(application, redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path") - - params = @valid_request - |> Map.delete("response_type") - |> Map.merge(%{"redirect_uri" => "https://example.com/path?param=1", "state" => 40_612}) - - assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == {:redirect, "https://example.com/path?error=invalid_request&error_description=The+request+is+missing+a+required+parameter%2C+includes+an+unsupported+parameter+value%2C+or+is+otherwise+malformed.¶m=1&state=40612"} + test "#preauthorize/3 redirect when missing response_type", %{ + resource_owner: resource_owner, + application: application + } do + QueryHelpers.change!(application, + redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path" + ) + + params = + @valid_request + |> Map.delete("response_type") + |> Map.merge(%{"redirect_uri" => "https://example.com/path?param=1", "state" => 40_612}) + + assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:redirect, + "https://example.com/path?error=invalid_request&error_description=The+request+is+missing+a+required+parameter%2C+includes+an+unsupported+parameter+value%2C+or+is+otherwise+malformed.¶m=1&state=40612"} end test "#preauthorize/3 error when unsupported response type", %{resource_owner: resource_owner} do params = Map.merge(@valid_request, %{"response_type" => "invalid"}) - assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == {:error, @invalid_response_type, :unprocessable_entity} + assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_response_type, :unprocessable_entity} end - test "#preauthorize/3 redirect when unsupported response_type", %{resource_owner: resource_owner, application: application} do - QueryHelpers.change!(application, redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path") - - params = @valid_request - |> Map.merge(%{"response_type" => "invalid"}) - |> Map.merge(%{"redirect_uri" => "https://example.com/path?param=1", "state" => 40_612}) - - assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == {:redirect, "https://example.com/path?error=unsupported_response_type&error_description=The+authorization+server+does+not+support+this+response+type.¶m=1&state=40612"} + test "#preauthorize/3 redirect when unsupported response_type", %{ + resource_owner: resource_owner, + application: application + } do + QueryHelpers.change!(application, + redirect_uri: "#{application.redirect_uri}\nhttps://example.com/path" + ) + + params = + @valid_request + |> Map.merge(%{"response_type" => "invalid"}) + |> Map.merge(%{"redirect_uri" => "https://example.com/path?param=1", "state" => 40_612}) + + assert Authorization.preauthorize(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:redirect, + "https://example.com/path?error=unsupported_response_type&error_description=The+authorization+server+does+not+support+this+response+type.¶m=1&state=40612"} end test "#authorize/3 error when missing response_type", %{resource_owner: resource_owner} do params = Map.delete(@valid_request, "response_type") - assert Authorization.authorize(resource_owner, params, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.authorize(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#authorize/3 rejects when unsupported response type", %{resource_owner: resource_owner} do params = Map.merge(@valid_request, %{"response_type" => "invalid"}) - assert Authorization.authorize(resource_owner, params, otp_app: :ex_oauth2_provider) == {:error, @invalid_response_type, :unprocessable_entity} + assert Authorization.authorize(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_response_type, :unprocessable_entity} end test "#deny/3 error when missing response_type", %{resource_owner: resource_owner} do params = Map.delete(@valid_request, "response_type") - assert Authorization.deny(resource_owner, params, otp_app: :ex_oauth2_provider) == {:error, @invalid_request, :bad_request} + assert Authorization.deny(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request, :bad_request} end test "#deny/3 rejects when unsupported response type", %{resource_owner: resource_owner} do params = Map.merge(@valid_request, %{"response_type" => "invalid"}) - assert Authorization.deny(resource_owner, params, otp_app: :ex_oauth2_provider) == {:error, @invalid_response_type, :unprocessable_entity} + assert Authorization.deny(resource_owner, params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_response_type, :unprocessable_entity} end end diff --git a/test/ex_oauth2_provider/oauth2/token/strategy/authorization_code_test.exs b/test/ex_oauth2_provider/oauth2/token/strategy/authorization_code_test.exs index 9b52b3df..e27ec6df 100644 --- a/test/ex_oauth2_provider/oauth2/token/strategy/authorization_code_test.exs +++ b/test/ex_oauth2_provider/oauth2/token/strategy/authorization_code_test.exs @@ -5,22 +5,28 @@ defmodule ExOauth2Provider.Token.Strategy.AuthorizationCodeTest do alias ExOauth2Provider.Test.{Fixtures, QueryHelpers} alias Dummy.OauthAccessTokens.OauthAccessToken - @client_id "Jf5rM8hQBc" - @client_secret "secret" - @code "code" - @redirect_uri "urn:ietf:wg:oauth:2.0:oob" - @valid_request %{"client_id" => @client_id, - "client_secret" => @client_secret, - "code" => @code, - "grant_type" => "authorization_code", - "redirect_uri" => @redirect_uri} - - @invalid_client_error %{error: :invalid_client, - error_description: "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." - } - @invalid_grant %{error: :invalid_grant, - error_description: "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client." - } + @client_id "Jf5rM8hQBc" + @client_secret "secret" + @code "code" + @redirect_uri "urn:ietf:wg:oauth:2.0:oob" + @valid_request %{ + "client_id" => @client_id, + "client_secret" => @client_secret, + "code" => @code, + "grant_type" => "authorization_code", + "redirect_uri" => @redirect_uri + } + + @invalid_client_error %{ + error: :invalid_client, + error_description: + "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + } + @invalid_grant %{ + error: :invalid_grant, + error_description: + "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client." + } setup do resource_owner = Fixtures.resource_owner() @@ -33,7 +39,11 @@ defmodule ExOauth2Provider.Token.Strategy.AuthorizationCodeTest do {:ok, %{resource_owner: resource_owner, application: application, access_grant: access_grant}} end - test "#grant/2 returns access token", %{resource_owner: resource_owner, application: application, access_grant: access_grant} do + test "#grant/2 returns access token", %{ + resource_owner: resource_owner, + application: application, + access_grant: access_grant + } do assert {:ok, body} = Token.grant(@valid_request, otp_app: :ex_oauth2_provider) access_token = QueryHelpers.get_latest_inserted(OauthAccessToken) @@ -45,7 +55,10 @@ defmodule ExOauth2Provider.Token.Strategy.AuthorizationCodeTest do refute is_nil(access_token.refresh_token) end - test "#grant/2 returns access token when client secret not required", %{resource_owner: resource_owner, application: application} do + test "#grant/2 returns access token when client secret not required", %{ + resource_owner: resource_owner, + application: application + } do QueryHelpers.change!(application, secret: "") valid_request_no_client_secret = Map.drop(@valid_request, ["client_secret"]) @@ -58,14 +71,25 @@ defmodule ExOauth2Provider.Token.Strategy.AuthorizationCodeTest do end test "#grant/2 returns access token with custom response handler" do - assert {:ok, body} = AuthorizationCode.grant(@valid_request, otp_app: :ex_oauth2_provider, access_token_response_body_handler: {__MODULE__, :access_token_response_body_handler}) + assert {:ok, body} = + AuthorizationCode.grant(@valid_request, + otp_app: :ex_oauth2_provider, + access_token_response_body_handler: + {__MODULE__, :access_token_response_body_handler} + ) + access_token = QueryHelpers.get_latest_inserted(OauthAccessToken) assert body.custom_attr == access_token.inserted_at end test "#grant/2 doesn't set refresh_token when ExOauth2Provider.Config.use_refresh_token? == false" do - assert {:ok, body} = AuthorizationCode.grant(@valid_request, otp_app: :ex_oauth2_provider, use_refresh_token: false) + assert {:ok, body} = + AuthorizationCode.grant(@valid_request, + otp_app: :ex_oauth2_provider, + use_refresh_token: false + ) + access_token = QueryHelpers.get_latest_inserted(OauthAccessToken) assert body.access_token == access_token.token @@ -74,10 +98,15 @@ defmodule ExOauth2Provider.Token.Strategy.AuthorizationCodeTest do test "#grant/2 can't use grant twice" do assert {:ok, _body} = Token.grant(@valid_request, otp_app: :ex_oauth2_provider) - assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_grant, :unprocessable_entity} + + assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_grant, :unprocessable_entity} end - test "#grant/2 doesn't duplicate access token", %{resource_owner: resource_owner, application: application} do + test "#grant/2 doesn't duplicate access token", %{ + resource_owner: resource_owner, + application: application + } do assert {:ok, body} = Token.grant(@valid_request, otp_app: :ex_oauth2_provider) access_grant = Fixtures.access_grant(application, resource_owner, "new_code", @redirect_uri) valid_request = Map.merge(@valid_request, %{"code" => access_grant.token}) @@ -89,51 +118,61 @@ defmodule ExOauth2Provider.Token.Strategy.AuthorizationCodeTest do test "#grant/2 error when invalid client" do request_invalid_client = Map.merge(@valid_request, %{"client_id" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 error when invalid secret" do request_invalid_client = Map.merge(@valid_request, %{"client_secret" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 error when invalid grant" do request_invalid_grant = Map.merge(@valid_request, %{"code" => "invalid"}) - assert Token.grant(request_invalid_grant, otp_app: :ex_oauth2_provider) == {:error, @invalid_grant, :unprocessable_entity} + assert Token.grant(request_invalid_grant, otp_app: :ex_oauth2_provider) == + {:error, @invalid_grant, :unprocessable_entity} end test "#grant/2 error when grant owned by another client", %{access_grant: access_grant} do new_application = Fixtures.application(uid: "new_app") QueryHelpers.change!(access_grant, application_id: new_application.id) - assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_grant, :unprocessable_entity} + assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_grant, :unprocessable_entity} end test "#grant/2 error when revoked grant", %{access_grant: access_grant} do QueryHelpers.change!(access_grant, revoked_at: DateTime.utc_now()) - assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_grant, :unprocessable_entity} + assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_grant, :unprocessable_entity} end test "#grant/2 error when grant expired", %{access_grant: access_grant} do - inserted_at = QueryHelpers.timestamp(OauthAccessToken, :inserted_at, seconds: -access_grant.expires_in) + inserted_at = + QueryHelpers.timestamp(OauthAccessToken, :inserted_at, seconds: -access_grant.expires_in) + QueryHelpers.change!(access_grant, inserted_at: inserted_at) - assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_grant, :unprocessable_entity} + assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_grant, :unprocessable_entity} end test "#grant/2 error when grant revoked", %{access_grant: access_grant} do AccessGrants.revoke(access_grant, otp_app: :ex_oauth2_provider) - assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_grant, :unprocessable_entity} + assert Token.grant(@valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_grant, :unprocessable_entity} end test "#grant/2 error when invalid redirect_uri" do request_invalid_redirect_uri = Map.merge(@valid_request, %{"redirect_uri" => "invalid"}) - assert Token.grant(request_invalid_redirect_uri, otp_app: :ex_oauth2_provider) == {:error, @invalid_grant, :unprocessable_entity} + assert Token.grant(request_invalid_redirect_uri, otp_app: :ex_oauth2_provider) == + {:error, @invalid_grant, :unprocessable_entity} end def access_token_response_body_handler(body, access_token) do diff --git a/test/ex_oauth2_provider/oauth2/token/strategy/client_credentials_test.exs b/test/ex_oauth2_provider/oauth2/token/strategy/client_credentials_test.exs index be3df2ae..829476dc 100644 --- a/test/ex_oauth2_provider/oauth2/token/strategy/client_credentials_test.exs +++ b/test/ex_oauth2_provider/oauth2/token/strategy/client_credentials_test.exs @@ -5,31 +5,39 @@ defmodule ExOauth2Provider.Token.Strategy.ClientCredentialsTest do alias ExOauth2Provider.Test.{Fixtures, QueryHelpers} alias Dummy.OauthAccessTokens.OauthAccessToken - @client_id "Jf5rM8hQBc" - @client_secret "secret" - @valid_request %{"client_id" => @client_id, - "client_secret" => @client_secret, - "grant_type" => "client_credentials", - "scope" => "app:read"} - @invalid_client_error %{error: :invalid_client, - error_description: "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." - } + @client_id "Jf5rM8hQBc" + @client_secret "secret" + @valid_request %{ + "client_id" => @client_id, + "client_secret" => @client_secret, + "grant_type" => "client_credentials", + "scope" => "app:read" + } + @invalid_client_error %{ + error: :invalid_client, + error_description: + "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + } setup do - application = Fixtures.application(uid: @client_id, secret: @client_secret, scopes: "app:read app:write") + application = + Fixtures.application(uid: @client_id, secret: @client_secret, scopes: "app:read app:write") + {:ok, %{application: application}} end test "#grant/2 error when invalid client" do request_invalid_client = Map.merge(@valid_request, %{"client_id" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 error when invalid secret" do request_invalid_client = Map.merge(@valid_request, %{"client_secret" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 returns access token", %{application: application} do diff --git a/test/ex_oauth2_provider/oauth2/token/strategy/password_test.exs b/test/ex_oauth2_provider/oauth2/token/strategy/password_test.exs index 5e569a9b..b983f9e8 100644 --- a/test/ex_oauth2_provider/oauth2/token/strategy/password_test.exs +++ b/test/ex_oauth2_provider/oauth2/token/strategy/password_test.exs @@ -5,68 +5,92 @@ defmodule ExOauth2Provider.Token.Strategy.PasswordTest do alias ExOauth2Provider.Test.{Fixtures, QueryHelpers} alias Dummy.OauthAccessTokens.OauthAccessToken - @client_id "Jf5rM8hQBc" - @client_secret "secret" - @username "testuser@example.com" - @password "secret" - @valid_request %{"client_id" => @client_id, - "client_secret" => @client_secret, - "grant_type" => "password", - "username" => @username, - "password" => @password} - @invalid_client_error %{error: :invalid_client, - error_description: "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." - } - @invalid_request_error %{error: :invalid_request, - error_description: "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." - } - @invalid_scope %{error: :invalid_scope, - error_description: "The requested scope is invalid, unknown, or malformed." - } + @client_id "Jf5rM8hQBc" + @client_secret "secret" + @username "testuser@example.com" + @password "secret" + @valid_request %{ + "client_id" => @client_id, + "client_secret" => @client_secret, + "grant_type" => "password", + "username" => @username, + "password" => @password + } + @invalid_client_error %{ + error: :invalid_client, + error_description: + "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + } + @invalid_request_error %{ + error: :invalid_request, + error_description: + "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." + } + @invalid_scope %{ + error: :invalid_scope, + error_description: "The requested scope is invalid, unknown, or malformed." + } setup do user = Fixtures.resource_owner(email: @username) - application = Fixtures.application(uid: @client_id, secret: @client_secret, scopes: "app:read app:write") + + application = + Fixtures.application(uid: @client_id, secret: @client_secret, scopes: "app:read app:write") + {:ok, %{user: user, application: application}} end test "#grant/2 error when invalid client" do request_invalid_client = Map.merge(@valid_request, %{"client_id" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 error when invalid secret" do request_invalid_client = Map.merge(@valid_request, %{"client_secret" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} request_invalid_client = Map.delete(@valid_request, "client_secret") - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 error when missing required values" do - Enum.each(["username", "password"], fn(k) -> + Enum.each(["username", "password"], fn k -> params = Map.delete(@valid_request, k) - assert Token.grant(params, otp_app: :ex_oauth2_provider) == {:error, @invalid_request_error, :bad_request} + + assert Token.grant(params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request_error, :bad_request} end) end test "#grant/2 error when invalid password" do params = Map.merge(@valid_request, %{"password" => "invalid"}) - assert Token.grant(params, otp_app: :ex_oauth2_provider) == {:error, :unauthorized, :unauthorized} + assert Token.grant(params, otp_app: :ex_oauth2_provider) == + {:error, :unauthorized, :unauthorized} end test "#grant/1 error when invalid scope" do params = Map.merge(@valid_request, %{"scope" => "invalid"}) - assert Token.grant(params, otp_app: :ex_oauth2_provider) == {:error, @invalid_scope, :unprocessable_entity} + assert Token.grant(params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_scope, :unprocessable_entity} end test "#grant/1 error when no password auth set" do - expected_error = %{error: :unsupported_grant_type, error_description: "The authorization grant type is not supported by the authorization server."} - - assert Password.grant(@valid_request, otp_app: :ex_oauth2_provider, password_auth: nil) == {:error, expected_error, :unprocessable_entity} + expected_error = %{ + error: :unsupported_grant_type, + error_description: + "The authorization grant type is not supported by the authorization server." + } + + assert Password.grant(@valid_request, otp_app: :ex_oauth2_provider, password_auth: nil) == + {:error, expected_error, :unprocessable_entity} end test "#grant/1 returns access token", %{user: user, application: application} do @@ -81,7 +105,10 @@ defmodule ExOauth2Provider.Token.Strategy.PasswordTest do refute is_nil(access_token.refresh_token) end - test "#grant/1 returns access token when only client_id required", %{user: user, application: application} do + test "#grant/1 returns access token when only client_id required", %{ + user: user, + application: application + } do QueryHelpers.change!(application, secret: "") params = Map.delete(@valid_request, "client_secret") @@ -95,14 +122,25 @@ defmodule ExOauth2Provider.Token.Strategy.PasswordTest do end test "#grant/1 returns access token with custom response handler" do - assert {:ok, body} = Password.grant(@valid_request, otp_app: :ex_oauth2_provider, access_token_response_body_handler: {__MODULE__, :access_token_response_body_handler}) + assert {:ok, body} = + Password.grant(@valid_request, + otp_app: :ex_oauth2_provider, + access_token_response_body_handler: + {__MODULE__, :access_token_response_body_handler} + ) + access_token = QueryHelpers.get_latest_inserted(OauthAccessToken) assert body.custom_attr == access_token.inserted_at end test "#grant/1 doesn't set refresh_token when ExOauth2Provider.Config.use_refresh_token? == false" do - assert {:ok, body} = Password.grant(@valid_request, otp_app: :ex_oauth2_provider, use_refresh_token: false) + assert {:ok, body} = + Password.grant(@valid_request, + otp_app: :ex_oauth2_provider, + use_refresh_token: false + ) + access_token = QueryHelpers.get_latest_inserted(OauthAccessToken) assert body.access_token == access_token.token diff --git a/test/ex_oauth2_provider/oauth2/token/strategy/refresh_token_test.exs b/test/ex_oauth2_provider/oauth2/token/strategy/refresh_token_test.exs index 77172f8e..f75f7ffa 100644 --- a/test/ex_oauth2_provider/oauth2/token/strategy/refresh_token_test.exs +++ b/test/ex_oauth2_provider/oauth2/token/strategy/refresh_token_test.exs @@ -5,65 +5,101 @@ defmodule ExOauth2Provider.Token.Strategy.RefreshTokenTest do alias ExOauth2Provider.Test.{Fixtures, QueryHelpers} alias Dummy.{OauthAccessTokens.OauthAccessToken, Repo} - @client_id "Jf5rM8hQBc" - @client_secret "secret" - @invalid_client_error %{error: :invalid_client, - error_description: "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." - } - @invalid_request_error %{error: :invalid_request, - error_description: "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." - } + @client_id "Jf5rM8hQBc" + @client_secret "secret" + @invalid_client_error %{ + error: :invalid_client, + error_description: + "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + } + @invalid_request_error %{ + error: :invalid_request, + error_description: + "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." + } setup do user = Fixtures.resource_owner() - application = Fixtures.application(resource_owner: user, uid: @client_id, secret: @client_secret, scopes: "app:read app:write") - access_token = Fixtures.access_token(resource_owner: user, application: application, use_refresh_token: true, scopes: "app:read") - valid_request = %{"client_id" => @client_id, - "client_secret" => @client_secret, - "grant_type" => "refresh_token", - "refresh_token" => access_token.refresh_token} + application = + Fixtures.application( + resource_owner: user, + uid: @client_id, + secret: @client_secret, + scopes: "app:read app:write" + ) + + access_token = + Fixtures.access_token( + resource_owner: user, + application: application, + use_refresh_token: true, + scopes: "app:read" + ) + + valid_request = %{ + "client_id" => @client_id, + "client_secret" => @client_secret, + "grant_type" => "refresh_token", + "refresh_token" => access_token.refresh_token + } + {:ok, %{access_token: access_token, valid_request: valid_request}} end test "#grant/2 error when invalid client", %{valid_request: valid_request} do request_invalid_client = Map.merge(valid_request, %{"client_id" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 error when invalid secret", %{valid_request: valid_request} do request_invalid_client = Map.merge(valid_request, %{"client_secret" => "invalid"}) - assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.grant(request_invalid_client, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#grant/2 error when missing token", %{valid_request: valid_request} do params = Map.delete(valid_request, "refresh_token") - assert Token.grant(params, otp_app: :ex_oauth2_provider) == {:error, @invalid_request_error, :bad_request} + assert Token.grant(params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request_error, :bad_request} end test "#grant/2 error when invalid token", %{valid_request: valid_request} do params = Map.merge(valid_request, %{"refresh_token" => "invalid"}) - assert Token.grant(params, otp_app: :ex_oauth2_provider) == {:error, @invalid_request_error, :bad_request} + assert Token.grant(params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request_error, :bad_request} end - test "#grant/2 error when access token owned by another client", %{valid_request: valid_request, access_token: access_token} do + test "#grant/2 error when access token owned by another client", %{ + valid_request: valid_request, + access_token: access_token + } do new_application = Fixtures.application(uid: "new_app") QueryHelpers.change!(access_token, application_id: new_application.id) - assert Token.grant(valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request_error, :bad_request} + assert Token.grant(valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request_error, :bad_request} end - test "#grant/2 error when access token has been revoked", %{valid_request: valid_request, access_token: access_token} do + test "#grant/2 error when access token has been revoked", %{ + valid_request: valid_request, + access_token: access_token + } do QueryHelpers.change!(access_token, revoked_at: DateTime.utc_now()) - assert Token.grant(valid_request, otp_app: :ex_oauth2_provider) == {:error, @invalid_request_error, :bad_request} + assert Token.grant(valid_request, otp_app: :ex_oauth2_provider) == + {:error, @invalid_request_error, :bad_request} end - test "#grant/2 returns access token", %{valid_request: valid_request, access_token: access_token} do + test "#grant/2 returns access token", %{ + valid_request: valid_request, + access_token: access_token + } do assert {:ok, new_access_token} = Token.grant(valid_request, otp_app: :ex_oauth2_provider) access_token = Repo.get_by(OauthAccessToken, id: access_token.id) @@ -73,19 +109,37 @@ defmodule ExOauth2Provider.Token.Strategy.RefreshTokenTest do assert new_access_token.resource_owner_id == access_token.resource_owner_id assert new_access_token.application_id == access_token.application_id assert new_access_token.scopes == access_token.scopes - assert new_access_token.expires_in == Config.access_token_expires_in(otp_app: :ex_oauth2_provider) + + assert new_access_token.expires_in == + Config.access_token_expires_in(otp_app: :ex_oauth2_provider) + assert new_access_token.previous_refresh_token == access_token.refresh_token assert AccessTokens.is_revoked?(access_token) end - test "#grant/2 returns access token with custom response handler", %{valid_request: valid_request} do - assert {:ok, body} = RefreshToken.grant(valid_request, otp_app: :ex_oauth2_provider, access_token_response_body_handler: {__MODULE__, :access_token_response_body_handler}) + test "#grant/2 returns access token with custom response handler", %{ + valid_request: valid_request + } do + assert {:ok, body} = + RefreshToken.grant(valid_request, + otp_app: :ex_oauth2_provider, + access_token_response_body_handler: + {__MODULE__, :access_token_response_body_handler} + ) + access_token = Repo.get_by(OauthAccessToken, token: body.access_token) assert body.custom_attr == access_token.inserted_at end - test "#grant/2 when refresh_token_revoked_on_use? == false", %{valid_request: valid_request, access_token: access_token} do - assert {:ok, new_access_token} = RefreshToken.grant(valid_request, otp_app: :ex_oauth2_provider, revoke_refresh_token_on_use: false) + test "#grant/2 when refresh_token_revoked_on_use? == false", %{ + valid_request: valid_request, + access_token: access_token + } do + assert {:ok, new_access_token} = + RefreshToken.grant(valid_request, + otp_app: :ex_oauth2_provider, + revoke_refresh_token_on_use: false + ) access_token = Repo.get_by(OauthAccessToken, id: access_token.id) new_access_token = Repo.get_by(OauthAccessToken, token: new_access_token.access_token) diff --git a/test/ex_oauth2_provider/oauth2/token/strategy/revoke_test.exs b/test/ex_oauth2_provider/oauth2/token/strategy/revoke_test.exs index a51ff8da..2994db9d 100644 --- a/test/ex_oauth2_provider/oauth2/token/strategy/revoke_test.exs +++ b/test/ex_oauth2_provider/oauth2/token/strategy/revoke_test.exs @@ -5,33 +5,54 @@ defmodule ExOauth2Provider.Token.Strategy.RevokeTest do alias ExOauth2Provider.Test.{Fixtures, QueryHelpers} alias Dummy.OauthAccessTokens.OauthAccessToken - @client_id "Jf5rM8hQBc" - @client_secret "secret" - @invalid_client_error %{error: :invalid_client, - error_description: "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." - } + @client_id "Jf5rM8hQBc" + @client_secret "secret" + @invalid_client_error %{ + error: :invalid_client, + error_description: + "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." + } setup do user = Fixtures.resource_owner() - application = Fixtures.application(resource_owner: user, uid: @client_id, secret: @client_secret, scopes: "app:read app:write") - access_token = Fixtures.access_token(resource_owner: user, application: application, use_refresh_token: true, scopes: "app:read") - valid_request = %{"client_id" => @client_id, - "client_secret" => @client_secret, - "token" => access_token.token} + application = + Fixtures.application( + resource_owner: user, + uid: @client_id, + secret: @client_secret, + scopes: "app:read app:write" + ) + + access_token = + Fixtures.access_token( + resource_owner: user, + application: application, + use_refresh_token: true, + scopes: "app:read" + ) + + valid_request = %{ + "client_id" => @client_id, + "client_secret" => @client_secret, + "token" => access_token.token + } + {:ok, %{access_token: access_token, valid_request: valid_request}} end test "#revoke/2 error when invalid client", %{valid_request: valid_request} do params = Map.merge(valid_request, %{"client_id" => "invalid"}) - assert Token.revoke(params, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.revoke(params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#revoke/2 error when invalid secret", %{valid_request: valid_request} do params = Map.merge(valid_request, %{"client_secret" => "invalid"}) - assert Token.revoke(params, otp_app: :ex_oauth2_provider) == {:error, @invalid_client_error, :unprocessable_entity} + assert Token.revoke(params, otp_app: :ex_oauth2_provider) == + {:error, @invalid_client_error, :unprocessable_entity} end test "#revoke/2 when missing token", %{valid_request: valid_request} do @@ -48,7 +69,10 @@ defmodule ExOauth2Provider.Token.Strategy.RevokeTest do refute AccessTokens.is_revoked?(QueryHelpers.get_latest_inserted(OauthAccessToken)) end - test "#revoke/2 when access token owned by another client", %{valid_request: valid_request, access_token: access_token} do + test "#revoke/2 when access token owned by another client", %{ + valid_request: valid_request, + access_token: access_token + } do new_application = Fixtures.application(uid: "new_app", secret: "new") QueryHelpers.change!(access_token, application_id: new_application.id) diff --git a/test/ex_oauth2_provider/oauth2/token_test.exs b/test/ex_oauth2_provider/oauth2/token_test.exs index f897e373..29610ba6 100644 --- a/test/ex_oauth2_provider/oauth2/token_test.exs +++ b/test/ex_oauth2_provider/oauth2/token_test.exs @@ -4,8 +4,8 @@ defmodule ExOauth2Provider.TokenTest do alias ExOauth2Provider.Token alias ExOauth2Provider.Test.Fixtures - @client_id "Jf5rM8hQBc" - @client_secret "secret" + @client_id "Jf5rM8hQBc" + @client_secret "secret" setup do application = Fixtures.application() @@ -13,13 +13,23 @@ defmodule ExOauth2Provider.TokenTest do end test "#grant/2 error when invalid grant_type" do - request_invalid_grant_type = Map.merge(%{"client_id" => @client_id, - "client_secret" => @client_secret, - "grant_type" => "client_credentials"}, - %{"grant_type" => "invalid"}) - expected_error = %{error: :unsupported_grant_type, - error_description: "The authorization grant type is not supported by the authorization server."} + request_invalid_grant_type = + Map.merge( + %{ + "client_id" => @client_id, + "client_secret" => @client_secret, + "grant_type" => "client_credentials" + }, + %{"grant_type" => "invalid"} + ) - assert Token.grant(request_invalid_grant_type, otp_app: :ex_oauth2_provider) == {:error, expected_error, :unprocessable_entity} + expected_error = %{ + error: :unsupported_grant_type, + error_description: + "The authorization grant type is not supported by the authorization server." + } + + assert Token.grant(request_invalid_grant_type, otp_app: :ex_oauth2_provider) == + {:error, expected_error, :unprocessable_entity} end end diff --git a/test/ex_oauth2_provider/plug/ensure_scopes_test.exs b/test/ex_oauth2_provider/plug/ensure_scopes_test.exs index 23aca9b9..ffde9151 100644 --- a/test/ex_oauth2_provider/plug/ensure_scopes_test.exs +++ b/test/ex_oauth2_provider/plug/ensure_scopes_test.exs @@ -61,7 +61,7 @@ defmodule ExOauth2Provider.Plug.EnsureScopesTest do defp run_plug(conn, scopes, opts) do access_token = %OauthAccessToken{token: "secret", scopes: scopes} - opts = Keyword.merge([handler: TestHandler], opts) + opts = Keyword.merge([handler: TestHandler], opts) conn |> Plug.set_current_access_token({:ok, access_token}) diff --git a/test/ex_oauth2_provider/plug/error_handler_test.exs b/test/ex_oauth2_provider/plug/error_handler_test.exs index d36c924e..82a4a123 100644 --- a/test/ex_oauth2_provider/plug/error_handler_test.exs +++ b/test/ex_oauth2_provider/plug/error_handler_test.exs @@ -84,8 +84,8 @@ defmodule ExOauth2Provider.Plug.ErrorHandlerTest do defp content_type(headers) do headers - |> Enum.filter(fn({k, _}) -> k == "content-type" end) - |> Enum.map(fn({_, v}) -> v end) + |> Enum.filter(fn {k, _} -> k == "content-type" end) + |> Enum.map(fn {_, v} -> v end) |> List.first() end end diff --git a/test/ex_oauth2_provider/plug/verify_header_test.exs b/test/ex_oauth2_provider/plug/verify_header_test.exs index daf115f5..b0541a6b 100644 --- a/test/ex_oauth2_provider/plug/verify_header_test.exs +++ b/test/ex_oauth2_provider/plug/verify_header_test.exs @@ -31,6 +31,7 @@ defmodule ExOauth2Provider.Plug.VerifyHeaderTest do test "at the default location", %{conn: conn, access_token: access_token} do opts = VerifyHeader.init(otp_app: :ex_oauth2_provider) + conn = conn |> Conn.put_req_header("authorization", access_token.token) @@ -42,6 +43,7 @@ defmodule ExOauth2Provider.Plug.VerifyHeaderTest do test "at a specified location", %{conn: conn, access_token: access_token} do opts = VerifyHeader.init(otp_app: :ex_oauth2_provider, key: :secret) + conn = conn |> Conn.put_req_header("authorization", access_token.token) @@ -53,6 +55,7 @@ defmodule ExOauth2Provider.Plug.VerifyHeaderTest do test "with a realm specified", %{conn: conn, access_token: access_token} do opts = VerifyHeader.init(otp_app: :ex_oauth2_provider, realm: "Bearer") + conn = conn |> Conn.put_req_header("authorization", "Bearer #{access_token.token}") @@ -62,10 +65,14 @@ defmodule ExOauth2Provider.Plug.VerifyHeaderTest do assert Plug.current_access_token(conn) == access_token end - test "with a realm specified and multiple auth headers", %{conn: conn, access_token: access_token} do + test "with a realm specified and multiple auth headers", %{ + conn: conn, + access_token: access_token + } do another_access_token = Fixtures.access_token() opts = VerifyHeader.init(otp_app: :ex_oauth2_provider, realm: "Client") + conn = conn |> Conn.put_req_header("authorization", "Bearer #{access_token.token}") @@ -76,7 +83,10 @@ defmodule ExOauth2Provider.Plug.VerifyHeaderTest do assert Plug.current_access_token(conn) == another_access_token end - test "pulls different tokens into different locations", %{conn: conn, access_token: access_token} do + test "pulls different tokens into different locations", %{ + conn: conn, + access_token: access_token + } do another_access_token = Fixtures.access_token() req_headers = [ @@ -86,6 +96,7 @@ defmodule ExOauth2Provider.Plug.VerifyHeaderTest do opts_1 = VerifyHeader.init(otp_app: :ex_oauth2_provider, realm: "Bearer") opts_2 = VerifyHeader.init(otp_app: :ex_oauth2_provider, realm: "Client", key: :client) + conn = conn |> Map.put(:req_headers, req_headers) diff --git a/test/ex_oauth2_provider_test.exs b/test/ex_oauth2_provider_test.exs index 4105e8d5..48150906 100644 --- a/test/ex_oauth2_provider_test.exs +++ b/test/ex_oauth2_provider_test.exs @@ -8,13 +8,19 @@ defmodule ExOauth2ProviderTest do describe "authenticate_token/2" do test "error when invalid" do - assert ExOauth2Provider.authenticate_token(nil, otp_app: :ex_oauth2_provider) == {:error, :token_inaccessible} - assert ExOauth2Provider.authenticate_token("secret", otp_app: :ex_oauth2_provider) == {:error, :token_not_found} + assert ExOauth2Provider.authenticate_token(nil, otp_app: :ex_oauth2_provider) == + {:error, :token_inaccessible} + + assert ExOauth2Provider.authenticate_token("secret", otp_app: :ex_oauth2_provider) == + {:error, :token_not_found} end test "authenticates" do access_token = Fixtures.access_token() - assert ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) == {:ok, access_token} + + assert ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) == + {:ok, access_token} + assert access_token.resource_owner end @@ -22,22 +28,40 @@ defmodule ExOauth2ProviderTest do application = Fixtures.application() access_token = Fixtures.application_access_token(application: application) - assert {:ok, access_token} = ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) + assert {:ok, access_token} = + ExOauth2Provider.authenticate_token(access_token.token, + otp_app: :ex_oauth2_provider + ) + refute access_token.resource_owner end test "revokes previous refresh token" do user = Fixtures.resource_owner() - access_token = Fixtures.access_token(resource_owner: user, use_refresh_token: true) - access_token2 = Fixtures.access_token(resource_owner: user, use_refresh_token: true, previous_refresh_token: access_token) + access_token = Fixtures.access_token(resource_owner: user, use_refresh_token: true) + + access_token2 = + Fixtures.access_token( + resource_owner: user, + use_refresh_token: true, + previous_refresh_token: access_token + ) + + assert {:ok, access_token} = + ExOauth2Provider.authenticate_token(access_token.token, + otp_app: :ex_oauth2_provider + ) - assert {:ok, access_token} = ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) access_token = Repo.get_by(OauthAccessToken, token: access_token.token) refute AccessTokens.is_revoked?(access_token) access_token2 = Repo.get_by(OauthAccessToken, token: access_token2.token) refute "" == access_token2.previous_refresh_token - assert {:ok, access_token2} = ExOauth2Provider.authenticate_token(access_token2.token, otp_app: :ex_oauth2_provider) + assert {:ok, access_token2} = + ExOauth2Provider.authenticate_token(access_token2.token, + otp_app: :ex_oauth2_provider + ) + access_token = Repo.get_by(OauthAccessToken, token: access_token.token) assert AccessTokens.is_revoked?(access_token) access_token2 = Repo.get_by(OauthAccessToken, token: access_token2.token) @@ -46,10 +70,21 @@ defmodule ExOauth2ProviderTest do test "doesn't revoke when refresh_token_revoked_on_use? == false" do user = Fixtures.resource_owner() - access_token = Fixtures.access_token(resource_owner: user, use_refresh_token: true) - access_token2 = Fixtures.access_token(resource_owner: user, use_refresh_token: true, previous_refresh_token: access_token) + access_token = Fixtures.access_token(resource_owner: user, use_refresh_token: true) + + access_token2 = + Fixtures.access_token( + resource_owner: user, + use_refresh_token: true, + previous_refresh_token: access_token + ) + + assert {:ok, access_token2} = + ExOauth2Provider.authenticate_token(access_token2.token, + otp_app: :ex_oauth2_provider, + revoke_refresh_token_on_use: false + ) - assert {:ok, access_token2} = ExOauth2Provider.authenticate_token(access_token2.token, otp_app: :ex_oauth2_provider, revoke_refresh_token_on_use: false) access_token = Repo.get_by(OauthAccessToken, token: access_token.token) refute AccessTokens.is_revoked?(access_token) access_token2 = Repo.get_by(OauthAccessToken, token: access_token2.token) @@ -59,14 +94,16 @@ defmodule ExOauth2ProviderTest do test "error when expired token" do access_token = Fixtures.access_token(expires_in: -1) - assert ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) == {:error, :token_inaccessible} + assert ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) == + {:error, :token_inaccessible} end test "error when revoked token" do access_token = Fixtures.access_token() AccessTokens.revoke(access_token) - assert ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) == {:error, :token_inaccessible} + assert ExOauth2Provider.authenticate_token(access_token.token, otp_app: :ex_oauth2_provider) == + {:error, :token_inaccessible} end end end diff --git a/test/mix/tasks/ex_oauth2_provider.gen.migration_test.exs b/test/mix/tasks/ex_oauth2_provider.gen.migration_test.exs index be281c84..e302f07e 100644 --- a/test/mix/tasks/ex_oauth2_provider.gen.migration_test.exs +++ b/test/mix/tasks/ex_oauth2_provider.gen.migration_test.exs @@ -10,7 +10,7 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.MigrationTest do @tmp_path Path.join(["tmp", inspect(Migration)]) @migrations_path Path.join(@tmp_path, "migrations") - @options ~w(-r #{inspect Repo}) + @options ~w(-r #{inspect(Repo)}) setup do File.rm_rf!(@tmp_path) @@ -27,18 +27,23 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.MigrationTest do file = @migrations_path |> Path.join(migration_file) |> File.read!() - assert file =~ "defmodule #{inspect Repo}.Migrations.CreateOauthTables do" + assert file =~ "defmodule #{inspect(Repo)}.Migrations.CreateOauthTables do" assert file =~ "use Ecto.Migration" assert file =~ "def change do" assert file =~ "add :owner_id, references(:users, on_delete: :nothing)" assert file =~ "add :resource_owner_id, references(:users, on_delete: :nothing)" refute file =~ "add :owner_id, references(:users, on_delete: :nothing, type: :binary_id)" - refute file =~ "add :resource_owner_id, references(:users, on_delete: :nothing, type: :binary_id)" + + refute file =~ + "add :resource_owner_id, references(:users, on_delete: :nothing, type: :binary_id)" + refute file =~ ":oauth_applications, primary_key: false" refute file =~ ":oauth_access_grants, primary_key: false" refute file =~ ":oauth_access_tokens, primary_key: false" refute file =~ "add :id, :binary_id, primary_key: true" - refute file =~ "add :application_id, references(:oauth_applications, on_delete: :nothing, type: binary_id)" + + refute file =~ + "add :application_id, references(:oauth_applications, on_delete: :nothing, type: binary_id)" end) end @@ -53,12 +58,17 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.MigrationTest do refute file =~ "add :owner_id, :integer, null: false" refute file =~ "add :resource_owner_id, :integer" assert file =~ "add :owner_id, references(:users, on_delete: :nothing, type: :binary_id)" - assert file =~ "add :resource_owner_id, references(:users, on_delete: :nothing, type: :binary_id)" + + assert file =~ + "add :resource_owner_id, references(:users, on_delete: :nothing, type: :binary_id)" + assert file =~ ":oauth_applications, primary_key: false" assert file =~ ":oauth_access_grants, primary_key: false" assert file =~ ":oauth_access_tokens, primary_key: false" assert file =~ "add :id, :binary_id, primary_key: true" - assert file =~ "add :application_id, references(:oauth_applications, on_delete: :nothing, type: :binary_id)" + + assert file =~ + "add :application_id, references(:oauth_applications, on_delete: :nothing, type: :binary_id)" end) end @@ -66,9 +76,11 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.MigrationTest do File.cd!(@tmp_path, fn -> Migration.run(@options) - assert_raise Mix.Error, "migration can't be created, there is already a migration file with name CreateOauthTables.", fn -> - Migration.run(@options) - end + assert_raise Mix.Error, + "migration can't be created, there is already a migration file with name CreateOauthTables.", + fn -> + Migration.run(@options) + end end) end end diff --git a/test/mix/tasks/ex_oauth2_provider.gen.schemas_test.exs b/test/mix/tasks/ex_oauth2_provider.gen.schemas_test.exs index d63bd4c6..009591ba 100644 --- a/test/mix/tasks/ex_oauth2_provider.gen.schemas_test.exs +++ b/test/mix/tasks/ex_oauth2_provider.gen.schemas_test.exs @@ -25,12 +25,24 @@ defmodule Mix.Tasks.ExOauth2Provider.Gen.SchemasTest do assert File.exists?(path) - module = Module.concat(["Test", Macro.camelize("oauth_#{file}s"), Macro.camelize("oauth_#{file}")]) - macro = Module.concat(["ExOauth2Provider", Macro.camelize("#{file}s"), Macro.camelize("#{file}")]) + module = + Module.concat([ + "Test", + Macro.camelize("oauth_#{file}s"), + Macro.camelize("oauth_#{file}") + ]) + + macro = + Module.concat([ + "ExOauth2Provider", + Macro.camelize("#{file}s"), + Macro.camelize("#{file}") + ]) + content = File.read!(path) - assert content =~ "defmodule #{inspect module} do" - assert content =~ "use #{inspect macro}, otp_app: :test" + assert content =~ "defmodule #{inspect(module)} do" + assert content =~ "use #{inspect(macro)}, otp_app: :test" assert content =~ "schema \"oauth_#{file}s\" do" assert content =~ "#{file}_fields()" end diff --git a/test/mix/tasks/ex_oauth2_provider.install_test.exs b/test/mix/tasks/ex_oauth2_provider.install_test.exs index 688b4016..bb34d67b 100644 --- a/test/mix/tasks/ex_oauth2_provider.install_test.exs +++ b/test/mix/tasks/ex_oauth2_provider.install_test.exs @@ -5,7 +5,7 @@ defmodule Mix.Tasks.ExOauth2Provider.InstallTest do alias Dummy.Repo @tmp_path Path.join(["tmp", inspect(Install)]) - @options ~w(--context-app test -r #{inspect Repo} --no-migration --no-scehmas) + @options ~w(--context-app test -r #{inspect(Repo)} --no-migration --no-scehmas) setup do File.rm_rf!(@tmp_path) @@ -18,10 +18,14 @@ defmodule Mix.Tasks.ExOauth2Provider.InstallTest do File.cd!(@tmp_path, fn -> Install.run(@options) - assert_received {:mix_shell, :info, ["ExOauth2Provider has been installed! Please append the following to `config/config.ex`:" <> msg]} + assert_received {:mix_shell, :info, + [ + "ExOauth2Provider has been installed! Please append the following to `config/config.ex`:" <> + msg + ]} assert msg =~ "config :test, ExOauth2Provider," - assert msg =~ " repo: #{inspect Repo}," + assert msg =~ " repo: #{inspect(Repo)}," assert msg =~ " resource_owner: Test.Users.User" end) end diff --git a/test/support/auth.ex b/test/support/auth.ex index 0b0fa420..8ec9adf4 100644 --- a/test/support/auth.ex +++ b/test/support/auth.ex @@ -7,9 +7,9 @@ defmodule Dummy.Auth do user = Repo.get_by(User, email: username) cond do - user == nil -> {:error, :no_user_found} - password == "secret" -> {:ok, user} - true -> {:error, :invalid_password} + user == nil -> {:error, :no_user_found} + password == "secret" -> {:ok, user} + true -> {:error, :invalid_password} end end end diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex index 988b1593..d6f1a08b 100644 --- a/test/support/fixtures.ex +++ b/test/support/fixtures.ex @@ -2,7 +2,14 @@ defmodule ExOauth2Provider.Test.Fixtures do @moduledoc false alias ExOauth2Provider.AccessTokens - alias Dummy.{OauthApplications.OauthApplication, OauthAccessGrants.OauthAccessGrant, Repo, Users.User} + + alias Dummy.{ + OauthApplications.OauthApplication, + OauthAccessGrants.OauthAccessGrant, + Repo, + Users.User + } + alias Ecto.Changeset def resource_owner(attrs \\ []) do @@ -16,13 +23,16 @@ defmodule ExOauth2Provider.Test.Fixtures do def application(attrs \\ []) do resource_owner = Keyword.get(attrs, :resource_owner) || resource_owner() - attrs = [ - owner_id: resource_owner.id, - uid: "test", - secret: "secret", - name: "OAuth Application", - redirect_uri: "urn:ietf:wg:oauth:2.0:oob", - scopes: "public read write"] + + attrs = + [ + owner_id: resource_owner.id, + uid: "test", + secret: "secret", + name: "OAuth Application", + redirect_uri: "urn:ietf:wg:oauth:2.0:oob", + scopes: "public read write" + ] |> Keyword.merge(attrs) |> Keyword.drop([:resource_owner]) @@ -46,12 +56,13 @@ defmodule ExOauth2Provider.Test.Fixtures do attrs |> Keyword.get(:application) |> Kernel.||(application()) - |> AccessTokens.create_application_token(Enum.into(attrs, %{}), otp_app: :ex_oauth2_provider) + |> AccessTokens.create_application_token(Enum.into(attrs, %{}), + otp_app: :ex_oauth2_provider + ) access_token end - def access_grant(application, user, code, redirect_uri) do attrs = [ expires_in: 900, diff --git a/test/support/lib/dummy/user.ex b/test/support/lib/dummy/user.ex index 59c851d7..9a403dd3 100644 --- a/test/support/lib/dummy/user.ex +++ b/test/support/lib/dummy/user.ex @@ -8,8 +8,8 @@ defmodule Dummy.Users.User do end schema "users" do - field :email, :string - has_many :tokens, Dummy.OauthAccessTokens.OauthAccessToken, foreign_key: :resource_owner_id + field(:email, :string) + has_many(:tokens, Dummy.OauthAccessTokens.OauthAccessToken, foreign_key: :resource_owner_id) timestamps() end diff --git a/test/support/mix/test_case.ex b/test/support/mix/test_case.ex index b957234f..5fc2f895 100644 --- a/test/support/mix/test_case.ex +++ b/test/support/mix/test_case.ex @@ -11,9 +11,9 @@ defmodule ExOauth2Provider.Mix.TestCase do setup _context do current_shell = Mix.shell() - on_exit fn -> + on_exit(fn -> Mix.shell(current_shell) - end + end) Mix.shell(Mix.Shell.Process) diff --git a/test/support/priv/migrations/1_create_user.exs b/test/support/priv/migrations/1_create_user.exs index d3586fd0..4fe5eeb6 100644 --- a/test/support/priv/migrations/1_create_user.exs +++ b/test/support/priv/migrations/1_create_user.exs @@ -4,9 +4,10 @@ defmodule ExOauth2Provider.Test.Repo.Migrations.CreateUser do def change do create table(:users, primary_key: is_nil(System.get_env("UUID"))) do if System.get_env("UUID") do - add :id, :binary_id, primary_key: true + add(:id, :binary_id, primary_key: true) end - add :email, :string + + add(:email, :string) timestamps() end diff --git a/test/support/priv/migrations/2_create_oauth_tables.exs b/test/support/priv/migrations/2_create_oauth_tables.exs index 45702729..bbc77935 100644 --- a/test/support/priv/migrations/2_create_oauth_tables.exs +++ b/test/support/priv/migrations/2_create_oauth_tables.exs @@ -1,6 +1,10 @@ require Mix.ExOauth2Provider.Migration binary_id = if System.get_env("UUID"), do: true, else: false + "CreateOauthTables" -|> Mix.ExOauth2Provider.Migration.gen("oauth", %{repo: ExOauth2Provider.Test.Repo, binary_id: binary_id}) +|> Mix.ExOauth2Provider.Migration.gen("oauth", %{ + repo: ExOauth2Provider.Test.Repo, + binary_id: binary_id +}) |> Code.eval_string() diff --git a/test/test_helper.exs b/test/test_helper.exs index 13150739..a7a93d53 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,5 +1,3 @@ -Logger.configure(level: :warn) - ExUnit.start() # Ensure that symlink to custom ecto priv directory exists