[#37] adding endpoint for creating users
This commit is contained in:
parent
7c80ed298b
commit
b5519a7d25
|
@ -1,6 +1,8 @@
|
||||||
/_build
|
/_build
|
||||||
/cover
|
/cover
|
||||||
/deps
|
/deps
|
||||||
|
/priv/keys
|
||||||
|
/priv/data
|
||||||
erl_crash.dump
|
erl_crash.dump
|
||||||
*.ez
|
*.ez
|
||||||
*.beam
|
*.beam
|
||||||
|
|
|
@ -47,9 +47,19 @@ config :poa_backend,
|
||||||
{:certfile, "priv/keys/localhost.cert"}
|
{:certfile, "priv/keys/localhost.cert"}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# this configuration is needed for Guardian, the Auth library
|
||||||
config :poa_backend, POABackend.Auth.Guardian,
|
config :poa_backend, POABackend.Auth.Guardian,
|
||||||
issuer: "poa_backend",
|
issuer: "poa_backend",
|
||||||
secret_key: "LQYmeqQfrphbxUjJltkwH4xnosLc+2S2e8KuYWctMenNY9bmgwnrH8r3ii9FP/8V"
|
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,
|
config :mnesia,
|
||||||
dir: '_build/test' # make sure this directory exists!
|
dir: '_build/test' # make sure this directory exists!
|
||||||
|
|
|
@ -71,11 +71,12 @@ defmodule POABackend.Auth do
|
||||||
This function authenticates a user/password pair
|
This function authenticates a user/password pair
|
||||||
"""
|
"""
|
||||||
@spec authenticate_user(String.t, String.t) :: {:ok, User.t} | {:error, :notvalid}
|
@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
|
alias Comeonin.Bcrypt
|
||||||
|
|
||||||
with user <- get_user(user),
|
with user <- get_user(user_name),
|
||||||
true <- Bcrypt.checkpw(password, user.password_hash)
|
true <- Bcrypt.checkpw(password, user.password_hash),
|
||||||
|
true <- user_active?(user)
|
||||||
do
|
do
|
||||||
{:ok, user}
|
{:ok, user}
|
||||||
else
|
else
|
||||||
|
@ -83,4 +84,69 @@ defmodule POABackend.Auth do
|
||||||
end
|
end
|
||||||
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
|
end
|
|
@ -32,6 +32,39 @@ defmodule POABackend.Auth.Router do
|
||||||
end
|
end
|
||||||
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
|
match _ do
|
||||||
send_resp(conn, 404, "")
|
send_resp(conn, 404, "")
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,8 @@ defmodule Auth.APITest do
|
||||||
@base_url "https://localhost:4003"
|
@base_url "https://localhost:4003"
|
||||||
@user "ferigis"
|
@user "ferigis"
|
||||||
@password "1234567890"
|
@password "1234567890"
|
||||||
|
@admin "admin1"
|
||||||
|
@admin_pwd "password12345678"
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
Utils.clear_db()
|
Utils.clear_db()
|
||||||
|
@ -107,6 +109,182 @@ defmodule Auth.APITest do
|
||||||
assert {404, :nobody} == result
|
assert {404, :nobody} == result
|
||||||
end
|
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
|
# 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