-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #80 from fleetyards/sso
Sso
- Loading branch information
Showing
39 changed files
with
1,344 additions
and
1,302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
apps/ex_fleet_yards/lib/ex_fleet_yards/plugs/api_authorization.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
defmodule ExFleetYards.Plugs.ApiAuthorization do | ||
@moduledoc """ | ||
This module provides plugs for authorization and authentication. | ||
## Plugs | ||
### `require_authenticated/2` | ||
Ensures that the user is authenticated by checking for a valid bearer token in | ||
the `authorization` header. | ||
It assigns the current token and user to the connection. | ||
### `authorize/2` | ||
Ensures that the user has the required OAuth2 scopes. | ||
Takes a list of required scopes as a parameter. | ||
""" | ||
|
||
@doc """ | ||
Ensures that the user is authenticated by checking for a valid bearer token in | ||
the `authorization` header. | ||
It assigns the current token and user to the connection. | ||
""" | ||
@callback require_authenticated(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() | ||
|
||
@doc """ | ||
Ensures that the user has the required OAuth2 scopes. | ||
Takes a list of required scopes as a parameter. | ||
""" | ||
@callback authorize(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() | ||
|
||
@doc """ | ||
Ensures that the user is authenticated by checking for a valid bearer token in | ||
the `authorization` header. | ||
It assigns the current token and user to the connection. | ||
""" | ||
def require_authenticated(conn, scopes) do | ||
impl().require_authenticated(conn, scopes) | ||
end | ||
|
||
@doc """ | ||
Ensures that the user has the required OAuth2 scopes. | ||
Takes a list of required scopes as a parameter. | ||
""" | ||
def authorize(conn, scopes) do | ||
impl().authorize(conn, scopes) | ||
end | ||
|
||
defp impl, | ||
do: | ||
ExFleetYards.Config.get( | ||
:ex_fleet_yards, | ||
:authorization_module, | ||
ExFleetYards.Plugs.AuthorizationBoruta | ||
) | ||
end |
75 changes: 75 additions & 0 deletions
75
apps/ex_fleet_yards/lib/ex_fleet_yards/plugs/authorization_boruta.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
defmodule ExFleetYards.Plugs.AuthorizationBoruta do | ||
@moduledoc """ | ||
This module provides plugs for authorization and authentication. | ||
## Plugs | ||
### `require_authenticated/2` | ||
Ensures that the user is authenticated by checking for a valid bearer token in | ||
the `authorization` header. | ||
It assigns the current token and user to the connection. | ||
### `authorize/2` | ||
Ensures that the user has the required OAuth2 scopes. | ||
Takes a list of required scopes as a parameter. | ||
""" | ||
|
||
import Plug.Conn | ||
|
||
alias ExFleetYards.Repo.Account | ||
|
||
alias Boruta.Oauth.Authorization | ||
alias Boruta.Oauth.Scope | ||
|
||
@doc """ | ||
Ensures that the user is authenticated by checking for a valid bearer token in | ||
the `authorization` header. | ||
It assigns the current token and user to the connection. | ||
""" | ||
@spec require_authenticated(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() | ||
def require_authenticated(conn, _opts) do | ||
with [authorization_header] <- get_req_header(conn, "authorization"), | ||
[_auth_header, bearer] <- Regex.run(~r/^Bearer\s+(.+)$/, authorization_header), | ||
{:ok, token} <- Authorization.AccessToken.authorize(value: bearer) do | ||
conn | ||
|> assign(:current_token, token) | ||
|> assign(:current_user, Account.get_user_by_sub(token.sub)) | ||
else | ||
_ -> | ||
conn | ||
|> put_status(:unauthorized) | ||
|> Phoenix.Controller.put_view(ExFleetYardsApi.ErrorJson) | ||
|> Phoenix.Controller.render("401.json") | ||
|> halt() | ||
end | ||
end | ||
|
||
@doc """ | ||
Ensures that the user has the required OAuth2 scopes. | ||
Takes a list of required scopes as a parameter. | ||
""" | ||
@spec authorize(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t() | ||
def authorize(conn, [_h | _t] = required_scopes) do | ||
current_scopes = Scope.split(conn.assigns[:current_token].scope) | ||
|
||
case Enum.empty?(required_scopes -- current_scopes) do | ||
true -> | ||
conn | ||
|
||
false -> | ||
conn | ||
|> put_status(:forbidden) | ||
|> Phoenix.Controller.put_view(ExFleetYardsApi.ErrorView) | ||
|> Phoenix.Controller.render("403.json", | ||
message: "You do not have the required scopes to access this resource" | ||
) | ||
|> halt() | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
apps/ex_fleet_yards/lib/ex_fleet_yards/repo/account/token_revocation.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
defmodule ExFleetYards.Repo.Account.TokenRevocation do | ||
@moduledoc """ | ||
Revoked token | ||
""" | ||
use TypedEctoSchema | ||
|
||
import Ecto.Changeset | ||
import Ecto.Query | ||
|
||
alias ExFleetYards.Repo | ||
alias ExFleetYards.Repo.Account | ||
|
||
@primary_key {:id, Ecto.UUID, []} | ||
|
||
typed_schema "user_token_revocations" do | ||
belongs_to :user, Account.User, type: Ecto.UUID | ||
field :jti, :string | ||
field :iat, :integer | ||
field :exp, :integer | ||
|
||
timestamps(updated_at: false) | ||
end | ||
|
||
@doc """ | ||
Revoke a token. | ||
This should not be called, but use ExFleetYards.Token.revoke_token/1 | ||
""" | ||
def revoke_token(attrs) do | ||
revoke_token_changeset(attrs) | ||
|> Repo.insert() | ||
end | ||
|
||
@doc """ | ||
Revoke all old tokens of a user. | ||
This should not be called, but use ExFleetYards.Token.revoke_user/1 | ||
""" | ||
def revoke_user(user_id) when is_binary(user_id) do | ||
%__MODULE__{} | ||
|> cast( | ||
%{ | ||
user_id: user_id, | ||
iat: Joken.current_time(), | ||
exp: Joken.current_time() + ExFleetYards.Token.revoke_exp() | ||
}, | ||
[:user_id, :iat, :exp] | ||
) | ||
|> Repo.insert() | ||
end | ||
|
||
@doc """ | ||
Revoke a specific token (changeset) | ||
""" | ||
def revoke_token_changeset(token \\ %__MODULE__{}, attrs) do | ||
token | ||
|> cast(attrs, [:user_id, :jti, :exp]) | ||
|> validate_required([:exp, :jti]) | ||
|> unique_constraint(:jti) | ||
end | ||
|
||
def verify_token_query(%{"sub" => user_id, "iat" => iat, "jti" => jti}) do | ||
from t in __MODULE__, where: t.jti == ^jti or (t.user_id == ^user_id and t.iat >= ^iat) | ||
end | ||
|
||
@doc """ | ||
Returns true if the token is not revoked | ||
""" | ||
def verify_token(token) do | ||
!Repo.exists?(verify_token_query(token)) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.