[#37] adding endpoint for creating users
This commit is contained in:
parent
7c80ed298b
commit
b5519a7d25
|
@ -1,6 +1,8 @@
|
|||
/_build
|
||||
/cover
|
||||
/deps
|
||||
/priv/keys
|
||||
/priv/data
|
||||
erl_crash.dump
|
||||
*.ez
|
||||
*.beam
|
||||
|
|
|
@ -47,9 +47,19 @@ config :poa_backend,
|
|||
{:certfile, "priv/keys/localhost.cert"}
|
||||
]
|
||||
|
||||
# this configuration is needed for Guardian, the Auth library
|
||||
config :poa_backend, POABackend.Auth.Guardian,
|
||||
issuer: "poa_backend",
|
||||
secret_key: "LQYmeqQfrphbxUjJltkwH4xnosLc+2S2e8KuYWctMenNY9bmgwnrH8r3ii9FP/8V"
|
||||
|
||||
# this is a list of admins/passwords for authorisation endpoints
|
||||
config :poa_backend,
|
||||
:admins,
|
||||
[
|
||||
{"admin1", "password12345678"},
|
||||
{"admin2", "password87654321"}
|
||||
]
|
||||
|
||||
# configuration for mnesia DB
|
||||
config :mnesia,
|
||||
dir: '_build/test' # make sure this directory exists!
|
||||
|
|
|
@ -71,11 +71,12 @@ defmodule POABackend.Auth do
|
|||
This function authenticates a user/password pair
|
||||
"""
|
||||
@spec authenticate_user(String.t, String.t) :: {:ok, User.t} | {:error, :notvalid}
|
||||
def authenticate_user(user, password) do
|
||||
def authenticate_user(user_name, password) do
|
||||
alias Comeonin.Bcrypt
|
||||
|
||||
with user <- get_user(user),
|
||||
true <- Bcrypt.checkpw(password, user.password_hash)
|
||||
with user <- get_user(user_name),
|
||||
true <- Bcrypt.checkpw(password, user.password_hash),
|
||||
true <- user_active?(user)
|
||||
do
|
||||
{:ok, user}
|
||||
else
|
||||
|
@ -83,4 +84,69 @@ defmodule POABackend.Auth do
|
|||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Authenticates an Admin
|
||||
"""
|
||||
@spec authenticate_admin(String.t, String.t) :: {:ok, :valid} | {:error, :notvalid}
|
||||
def authenticate_admin(admin_name, password) do
|
||||
with admins <- Application.get_env(:poa_backend, :admins),
|
||||
true <- Enum.member?(admins, {admin_name, password})
|
||||
do
|
||||
{:ok, :valid}
|
||||
else
|
||||
_error -> {:error, :notvalid}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Generates a valid user name randomply
|
||||
"""
|
||||
@spec generate_user_name() :: String.t
|
||||
def generate_user_name do
|
||||
8
|
||||
|> random_string()
|
||||
|> generate_user_name()
|
||||
end
|
||||
|
||||
@doc """
|
||||
This function is exported for testing purposes
|
||||
"""
|
||||
@spec generate_user_name(String.t) :: String.t
|
||||
def generate_user_name(user_name) do
|
||||
case valid_user_name?(user_name) do
|
||||
true -> user_name
|
||||
false -> generate_user_name()
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Generates a password randomply
|
||||
"""
|
||||
@spec generate_password() :: String.t
|
||||
def generate_password do
|
||||
random_string(15)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Validates if a given user name is valid or not. It is valid if doesn't exist a user
|
||||
with that name in the database already
|
||||
"""
|
||||
@spec valid_user_name?(String.t) :: Boolean.t
|
||||
def valid_user_name?(user_name) do
|
||||
case get_user(user_name) do
|
||||
nil -> true
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------
|
||||
# Private Functions
|
||||
# ---------------------------------------
|
||||
|
||||
defp random_string(length) do
|
||||
length
|
||||
|> :crypto.strong_rand_bytes()
|
||||
|> Base.url_encode64
|
||||
|> binary_part(0, length)
|
||||
end
|
||||
end
|
|
@ -32,6 +32,39 @@ defmodule POABackend.Auth.Router do
|
|||
end
|
||||
end
|
||||
|
||||
post "/user" do
|
||||
with {"authorization", "Basic " <> base64} <- List.keyfind(conn.req_headers, "authorization", 0),
|
||||
{:ok, decoded64} <- Base.decode64(base64),
|
||||
[admin_name, admin_password] <- String.split(decoded64, ":"),
|
||||
{:ok, :valid} <- Auth.authenticate_admin(admin_name, admin_password)
|
||||
do
|
||||
|
||||
user_name = Map.get(conn.params, "user-name", Auth.generate_user_name())
|
||||
password = Map.get(conn.params, "password", Auth.generate_password())
|
||||
|
||||
case Auth.valid_user_name?(user_name) do
|
||||
true ->
|
||||
{:ok, _user} = Auth.create_user(user_name, password)
|
||||
|
||||
{:ok, result} =
|
||||
%{:'user-name' => user_name,
|
||||
:password => password}
|
||||
|> Poison.encode
|
||||
|
||||
send_resp(conn, 200, result)
|
||||
false ->
|
||||
conn
|
||||
|> send_resp(409, "")
|
||||
|> halt
|
||||
end
|
||||
else
|
||||
_error ->
|
||||
conn
|
||||
|> send_resp(401, "")
|
||||
|> halt
|
||||
end
|
||||
end
|
||||
|
||||
match _ do
|
||||
send_resp(conn, 404, "")
|
||||
end
|
||||
|
|
|
@ -6,6 +6,8 @@ defmodule Auth.APITest do
|
|||
@base_url "https://localhost:4003"
|
||||
@user "ferigis"
|
||||
@password "1234567890"
|
||||
@admin "admin1"
|
||||
@admin_pwd "password12345678"
|
||||
|
||||
setup do
|
||||
Utils.clear_db()
|
||||
|
@ -107,6 +109,182 @@ defmodule Auth.APITest do
|
|||
assert {404, :nobody} == result
|
||||
end
|
||||
|
||||
# ----------------------------------------
|
||||
# /user Endpoint Tests
|
||||
# ----------------------------------------
|
||||
|
||||
test "trying to create a user with wrong Admin Credentials [JSON]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/json"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> "wrongpassword")}
|
||||
]
|
||||
|
||||
result =
|
||||
%{:'agent-id' => "agentID"}
|
||||
|> Poison.encode!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert {401, :nobody} == result
|
||||
end
|
||||
|
||||
test "trying to create a user with wrong Admin Credentials [MSGPACK]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/msgpack"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> "wrongpassword")}
|
||||
]
|
||||
|
||||
result =
|
||||
%{:'agent-id' => "agentID"}
|
||||
|> Msgpax.pack!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert {401, :nobody} == result
|
||||
end
|
||||
|
||||
test "create a user without credentials [JSON]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/json"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
|
||||
{200, %{"user-name" => user_name, "password" => password}} =
|
||||
%{:'agent-id' => "agentID"}
|
||||
|> Poison.encode!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert Auth.authenticate_user(user_name, password)
|
||||
end
|
||||
|
||||
test "create a user without credentials [MSGPACK]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/msgpack"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
|
||||
{200, %{"user-name" => user_name, "password" => password}} =
|
||||
%{:'agent-id' => "agentID"}
|
||||
|> Msgpax.pack!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert Auth.authenticate_user(user_name, password)
|
||||
end
|
||||
|
||||
test "create a user with user_name [JSON]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/json"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
user_name = "newUserName"
|
||||
|
||||
{200, %{"user-name" => ^user_name, "password" => password}} =
|
||||
%{:'agent-id' => "agentID", :'user-name' => user_name}
|
||||
|> Poison.encode!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert Auth.authenticate_user(user_name, password)
|
||||
end
|
||||
|
||||
test "create a user with user_name [MSGPACK]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/msgpack"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
user_name = "newUserName"
|
||||
|
||||
{200, %{"user-name" => ^user_name, "password" => password}} =
|
||||
%{:'agent-id' => "agentID", :'user-name' => user_name}
|
||||
|> Msgpax.pack!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert Auth.authenticate_user(user_name, password)
|
||||
end
|
||||
|
||||
test "create a user with user_name and password [JSON]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/json"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
user_name = "newUserName2"
|
||||
password = "mypasswordfornewuser"
|
||||
|
||||
{200, %{"user-name" => ^user_name, "password" => ^password}} =
|
||||
%{:'agent-id' => "agentID",
|
||||
:'user-name' => user_name,
|
||||
:password => password}
|
||||
|> Poison.encode!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert Auth.authenticate_user(user_name, password)
|
||||
end
|
||||
|
||||
test "create a user with user_name and password [MSGPACK]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/msgpack"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
user_name = "newUserName2"
|
||||
password = "mypasswordfornewuser"
|
||||
|
||||
{200, %{"user-name" => ^user_name, "password" => ^password}} =
|
||||
%{:'agent-id' => "agentID",
|
||||
:'user-name' => user_name,
|
||||
:password => password}
|
||||
|> Msgpax.pack!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert Auth.authenticate_user(user_name, password)
|
||||
end
|
||||
|
||||
test "create user which already exists [JSON]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/json"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
|
||||
result =
|
||||
%{:'agent-id' => "agentID",
|
||||
:'user-name' => @user}
|
||||
|> Poison.encode!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert {409, :nobody} == result
|
||||
end
|
||||
|
||||
test "create user which already exists [MSGPACK]" do
|
||||
url = @base_url <> "/user"
|
||||
mime_type = "application/msgpack"
|
||||
headers = [
|
||||
{"Content-Type", mime_type},
|
||||
{"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
|
||||
]
|
||||
|
||||
result =
|
||||
%{:'agent-id' => "agentID",
|
||||
:'user-name' => @user}
|
||||
|> Msgpax.pack!()
|
||||
|> post(url, headers)
|
||||
|
||||
assert {409, :nobody} == result
|
||||
end
|
||||
|
||||
# ----------------------------------------
|
||||
# Internal functions
|
||||
# ----------------------------------------
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
defmodule Auth.AuthTest do
|
||||
use ExUnit.Case
|
||||
alias POABackend.Auth
|
||||
alias POABackend.Ancillary.Utils
|
||||
|
||||
setup do
|
||||
Utils.clear_db()
|
||||
|
||||
on_exit fn ->
|
||||
Utils.clear_db()
|
||||
end
|
||||
|
||||
[]
|
||||
end
|
||||
|
||||
test "create a new user" do
|
||||
alias Comeonin.Bcrypt
|
||||
user_name = "ferigis"
|
||||
password = "mypassword"
|
||||
|
||||
{:ok, user} = Auth.create_user(user_name, password)
|
||||
|
||||
assert Bcrypt.checkpw(password, user.password_hash)
|
||||
|
||||
{:error, :already_exists} = Auth.create_user(user_name, "mypassword")
|
||||
end
|
||||
|
||||
test "get a user" do
|
||||
user_name = "ferigis"
|
||||
password = "mypassword"
|
||||
|
||||
{:ok, user} = Auth.create_user(user_name, password)
|
||||
|
||||
assert user == Auth.get_user(user_name)
|
||||
|
||||
assert nil == Auth.get_user("otheruser")
|
||||
end
|
||||
|
||||
test "remove a user" do
|
||||
user_name = "ferigis"
|
||||
password = "mypassword"
|
||||
|
||||
assert nil == Auth.get_user(user_name)
|
||||
|
||||
{:ok, user} = Auth.create_user(user_name, password)
|
||||
|
||||
assert user == Auth.get_user(user_name)
|
||||
|
||||
:ok = Auth.remove_user(user)
|
||||
|
||||
assert nil == Auth.get_user(user_name)
|
||||
end
|
||||
|
||||
test "activate/deactivate a user" do
|
||||
user_name = "ferigis"
|
||||
password = "mypassword"
|
||||
|
||||
|
||||
{:ok, user} = Auth.create_user(user_name, password)
|
||||
|
||||
assert Auth.user_active?(user)
|
||||
assert {:ok, user} == Auth.authenticate_user(user_name, password)
|
||||
|
||||
{:ok, _} = Auth.deactivate_user(user)
|
||||
user = Auth.get_user(user_name)
|
||||
|
||||
refute Auth.user_active?(user)
|
||||
assert {:error, :notvalid} == Auth.authenticate_user(user_name, password)
|
||||
|
||||
{:ok, _} = Auth.activate_user(user)
|
||||
user = Auth.get_user(user_name)
|
||||
|
||||
assert Auth.user_active?(user)
|
||||
assert {:ok, user} == Auth.authenticate_user(user_name, password)
|
||||
end
|
||||
|
||||
test "authenticate an admin" do
|
||||
{:ok, :valid} = Auth.authenticate_admin("admin1", "password12345678")
|
||||
{:ok, :valid} = Auth.authenticate_admin("admin2", "password87654321")
|
||||
{:error, :notvalid} = Auth.authenticate_admin("admin2", "wrong_password")
|
||||
end
|
||||
|
||||
test "generate user_name [coverage]" do
|
||||
user_name = "ferigis"
|
||||
password = "mypassword"
|
||||
|
||||
{:ok, _user} = Auth.create_user(user_name, password)
|
||||
|
||||
user_name2 = Auth.generate_user_name(user_name)
|
||||
|
||||
refute user_name == user_name2
|
||||
end
|
||||
end
|
|
@ -1,63 +0,0 @@
|
|||
defmodule Auth.UserTest do
|
||||
use ExUnit.Case
|
||||
alias POABackend.Auth
|
||||
alias POABackend.Ancillary.Utils
|
||||
|
||||
setup do
|
||||
Utils.clear_db()
|
||||
|
||||
on_exit fn ->
|
||||
Utils.clear_db()
|
||||
end
|
||||
|
||||
[]
|
||||
end
|
||||
|
||||
test "create a new user" do
|
||||
alias Comeonin.Bcrypt
|
||||
|
||||
password = "mypassword"
|
||||
|
||||
{:ok, user} = Auth.create_user("ferigis", password)
|
||||
|
||||
assert Bcrypt.checkpw(password, user.password_hash)
|
||||
|
||||
{:error, :already_exists} = Auth.create_user("ferigis", "mypassword")
|
||||
end
|
||||
|
||||
test "get a user" do
|
||||
{:ok, user} = Auth.create_user("ferigis", "mypassword")
|
||||
|
||||
assert user == Auth.get_user("ferigis")
|
||||
|
||||
assert nil == Auth.get_user("otheruser")
|
||||
end
|
||||
|
||||
test "remove a user" do
|
||||
assert nil == Auth.get_user("ferigis")
|
||||
|
||||
{:ok, user} = Auth.create_user("ferigis", "mypassword")
|
||||
|
||||
assert user == Auth.get_user("ferigis")
|
||||
|
||||
:ok = Auth.remove_user(user)
|
||||
|
||||
assert nil == Auth.get_user("ferigis")
|
||||
end
|
||||
|
||||
test "activate/deactivate a user" do
|
||||
{:ok, user} = Auth.create_user("ferigis", "mypassword")
|
||||
|
||||
assert Auth.user_active?(user)
|
||||
|
||||
{:ok, _} = Auth.deactivate_user(user)
|
||||
user = Auth.get_user("ferigis")
|
||||
|
||||
refute Auth.user_active?(user)
|
||||
|
||||
{:ok, _} = Auth.activate_user(user)
|
||||
user = Auth.get_user("ferigis")
|
||||
|
||||
assert Auth.user_active?(user)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue