Current section

Files

Jump to
blossom lib blossom auth_plug.ex
Raw

lib/blossom/auth_plug.ex

defmodule Blossom.AuthPlug do
alias Blossom.{AuthPlug, Tokens, Utils}
alias Plug.Conn
def users_controller(config, opts) do
Utils.option_or_key_config(config, opts, :users_controller, nil)
end
def jwt_key(config, opts) do
Utils.option_or_key_config(config, opts, :jwt_key, :jwt)
end
def realm(config, opts, otp_app) do
Utils.option_or_key_config(config, opts, :realm, otp_app)
end
def user_key(config, opts) do
Utils.option_or_key_config(config, opts, :user_key, :user)
end
def init(opts), do: opts
def get_opts(options) do
config = Application.get_env(options[:otp_app], Blossom)
[
audience: Utils.audience(config, options, options[:otp_app]),
expiration: Utils.expiration(config, options),
jwt_key: AuthPlug.jwt_key(config, options),
realm: AuthPlug.realm(config, options, options[:otp_app]),
secret: Utils.secret(config, options),
users_controller: AuthPlug.users_controller(config, options),
user_key: AuthPlug.user_key(config, options)
]
end
def get_header(conn) do
List.first(Conn.get_req_header(conn, "authorization"))
end
def token_from_header(header) do
fragments = String.split(header)
if String.downcase(List.first(fragments)) == "bearer" do
{:ok, List.last(fragments)}
else
{:error, :no_bearer_token}
end
end
def get_token(conn) do
case AuthPlug.get_header(conn) do
nil -> {:error, :no_authorization_header}
header -> AuthPlug.token_from_header(header)
end
end
def unauthorized_header(conn, error, realm) do
conn
|> Conn.put_resp_header(
"www-authenticate",
"Bearer realm=\"#{realm}\", error=\"#{error}\""
)
end
def send_401(conn, error, opts) do
conn
|> AuthPlug.unauthorized_header(error, opts[:realm])
|> Conn.put_resp_content_type("application/json")
|> Conn.send_resp(401, Poison.encode!(%{"message" => error}))
|> Conn.halt()
end
def get_user(controller, user_id) do
params = %{"id" => user_id, "blocked" => false}
case controller.get(params, :public) do
[] -> {:error, :unknown_user}
[user] -> {:ok, user}
end
end
def put_user(conn, fields, opts) do
case AuthPlug.get_user(opts[:users_controller], fields["sub"]) do
{:ok, user} ->
conn
|> Conn.put_private(opts[:jwt_key], fields)
|> Conn.put_private(opts[:user_key], user)
{:error, error} ->
AuthPlug.send_401(conn, error, opts)
end
end
def put_private(outcome, conn, opts) do
case outcome do
{:ok, fields} -> AuthPlug.put_user(conn, fields, opts)
{:error, error} -> AuthPlug.send_401(conn, error, opts)
end
end
def handle_auth(outcome, conn, opts) do
case outcome do
{:ok, token} ->
token
|> Tokens.verify(opts)
|> AuthPlug.put_private(conn, opts)
{:error, error} ->
AuthPlug.send_401(conn, error, opts)
end
end
def call(conn, options) do
opts = AuthPlug.get_opts(options)
conn
|> AuthPlug.get_token()
|> AuthPlug.handle_auth(conn, opts)
end
end