Current section

Files

Jump to
openmaize lib openmaize.ex
Raw

lib/openmaize.ex

defmodule Openmaize do
@moduledoc """
This module handles the initial call to Openmaize and then calls the
relevant module for handling authentication and authorization, logging
in or logging out.
If the path is for the login page and the method is "POST", the
connection is redirected to the Openmaize.Login module. If the
method is "GET", the user is allowed to go to the login page.
If the path is for the logout page, the connection is redirected
to the Openmaize.Logout module, which handles the logout and redirects
the user to the home page.
For any other path, including unprotected paths, the connection is
redirected to the Openmaize.Auth module, which handles user
authentication and resource authorization.
## Phoenix integration
The `current_user` variable is set for every path. This means that
you can access `@current_user` in any of your templates. If nobody
is logged in, `current_user` is set to nil.
"""
import Plug.Conn
import Openmaize.Errors
alias Openmaize.Auth
alias Openmaize.Config
alias Openmaize.Login
alias Openmaize.Logout
@behaviour Plug
def init(opts), do: opts
@doc """
Function to check the token provided. If there is no token, or if the
token is invalid, the user is redirected to the login page.
If the path is for the login or logout page, the user is redirected
to that page straight away.
## Options
There are two options available: `redirects` and `check`.
`redirects` is set to true by default, which is probably what you need
for an application in the browser. For an api, though, or a Single Page
Application, you will probably just want responses without redirects.
`check` is for a function to perform extra checks before authenticating
the user. This option is available so that user authentication and
resource authorization can be more easily customized. There are some
examples of this kind of function in the Openmaize.IdCheck module.
## Examples
Call openmaize with no options:
plug Openmaize
Call openmaize for an api with a further id check:
import Openmaize.IdCheck
plug Openmaize, redirects: false, check: &id_noedit/4
"""
def call(%{path_info: path_info} = conn, opts) do
opts = {Keyword.get(opts, :redirects), Keyword.get(opts, :check)}
case Enum.at(path_info, -1) do
"login" -> handle_login(conn, opts)
"logout" -> handle_logout(conn, opts)
_ -> handle_auth(conn, opts)
end
end
defp handle_login(%{method: "POST"} = conn, opts), do: Login.call(conn, opts)
defp handle_login(conn, _opts), do: assign(conn, :current_user, nil)
defp handle_logout(conn, opts), do: assign(conn, :current_user, nil) |> Logout.call(opts)
defp handle_auth(conn, {false, _check} = opts) do
Auth.call(conn, opts) |> auth(conn, opts)
end
defp handle_auth(conn, opts) do
Auth.call(conn, [storage: Config.storage_method]) |> auth(conn, opts)
end
defp auth({:ok, data}, conn, _), do: assign(conn, :current_user, data)
defp auth({:ok, data, _, _}, conn, {_, nil}), do: assign(conn, :current_user, data)
defp auth({:ok, data, path, match}, conn, {_, func}) do
func.(conn, data, path, match) |> auth(conn, {nil, nil})
end
defp auth({:error, message}, conn, {false, _}), do: send_error(conn, 401, message)
defp auth({:error, message}, conn, _), do: handle_error(conn, message)
defp auth({:error, _, message}, conn, {false, _}), do: send_error(conn, 403, message)
defp auth({:error, role, message}, conn, _), do: handle_error(conn, role, message)
end