diff --git a/doc/POABackend.Auth.REST.html b/doc/POABackend.Auth.REST.html
index 803e8f1..2b45bd7 100644
--- a/doc/POABackend.Auth.REST.html
+++ b/doc/POABackend.Auth.REST.html
@@ -170,9 +170,9 @@ content-length: 362
cache-control: max-age=0, private, must-revalidate
{"token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJwb2FfYmFja2VuZCIsImV4cCI6MTUzMzkzNjMwNiwiaWF0IjoxNTMzOTMyNzA2LCJpc3MiOiJwb2FfYmFja2VuZCIsImp0aSI6ImI0MzBkNTMwLWExZDYtNDk1Yy1hMjYyLThjNTcxMmM1OTM4YSIsIm5iZiI6MTUzMzkzMjcwNSwic3ViIjoiUmp1YURzdi0iLCJ0eXAiOiJhY2Nlc3MifQ.E3gqpCxY5wAAhZwcr7vZVLcC7X-bSHcXfX6NgeJc-LMbpcDgJvZgcgYQ-VTIkulb2mWw_Fjc7sXVwYMeIIliMg"}
-
-
- User Endpoint
+
+
+ Create User Endpoint
This Endpoint is needed in order to add a new user. Only Admin people can do that.
@@ -352,6 +352,83 @@ server: Cowboy
date: Tue, 04 Sep 2018 13:49:45 GMT
content-length: 0
cache-control: max-age=0, private, must-revalidate
+
+
+ Update User Endpoint
+
+
+This Endpoint is needed in order to update a user. Currently only the active
property can be updated. If a user is set to active: false
means
+it was banned. We can use this enpoint in order to ban or unban users too.
+PATCH /user/:username
+
+
+
+
+
+
+
+HTTP header | Values |
+
+
+
+content-type | application/json or application/msgpack |
+
+
+authorization | Basic encodeBase64(adminname + “:” + password) |
+
+
+
+
+
+
+
+
+
+Payload | Value |
+
+
+
+JSON | {“active” : boolean()} |
+
+
+MessagePack | Same as JSON but packed with MessagePack |
+
+
+Response
+
+
+
+
+
+
+
+CODE | Description |
+
+
+
+204 | Success |
+
+
+401 | Authentication failed |
+
+
+404 | The user doesn’t exist |
+
+
+415 | Unsupported Media Type (only application/json and application/msgpack allowed) |
+
+
+422 | Unprocessable entity (the active value is not a boolean) |
+
+
+Example:
+curl -i -X PATCH -H "Authorization: Basic YWRtaW4xOnBhc3N3b3JkMTIzNDU2Nzg=" -H "Content-Type: application/json" -d '{"active":false}' https://localhost:4003/user/cZFxFfNT --insecure
+
+HTTP/1.1 204 No Content
+server: Cowboy
+date: Wed, 05 Sep 2018 13:38:32 GMT
+content-length: 0
+cache-control: max-age=0, private, must-revalidate
Blacklist Token Endpoint
diff --git a/lib/poa_backend/auth/rest.ex b/lib/poa_backend/auth/rest.ex
index ace47f0..8fb1f81 100644
--- a/lib/poa_backend/auth/rest.ex
+++ b/lib/poa_backend/auth/rest.ex
@@ -57,7 +57,7 @@ defmodule POABackend.Auth.REST do
{"token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJwb2FfYmFja2VuZCIsImV4cCI6MTUzMzkzNjMwNiwiaWF0IjoxNTMzOTMyNzA2LCJpc3MiOiJwb2FfYmFja2VuZCIsImp0aSI6ImI0MzBkNTMwLWExZDYtNDk1Yy1hMjYyLThjNTcxMmM1OTM4YSIsIm5iZiI6MTUzMzkzMjcwNSwic3ViIjoiUmp1YURzdi0iLCJ0eXAiOiJhY2Nlc3MifQ.E3gqpCxY5wAAhZwcr7vZVLcC7X-bSHcXfX6NgeJc-LMbpcDgJvZgcgYQ-VTIkulb2mWw_Fjc7sXVwYMeIIliMg"}
```
- ## User Endpoint
+ ## Create User Endpoint
This Endpoint is needed in order to add a new user. Only Admin people can do that.
@@ -170,6 +170,45 @@ defmodule POABackend.Auth.REST do
cache-control: max-age=0, private, must-revalidate
```
+ ## Update User Endpoint
+
+ This Endpoint is needed in order to update a user. Currently only the `active` property can be updated. If a user is set to `active: false` means
+ it was banned. We can use this enpoint in order to ban or unban users too.
+
+ `PATCH /user/:username`
+
+ HTTP header | Values
+ -- | --
+ content-type | application/json or application/msgpack
+ authorization | Basic encodeBase64(adminname + “:” + password)
+
+ Payload | Value
+ -- | --
+ JSON | {"active" : boolean()}
+ MessagePack | Same as JSON but packed with MessagePack
+
+ Response
+
+ CODE | Description
+ -- | --
+ 204 | Success
+ 401 | Authentication failed
+ 404 | The user doesn't exist
+ 415 | Unsupported Media Type (only application/json and application/msgpack allowed)
+ 422 | Unprocessable entity (the active value is not a boolean)
+
+ Example:
+
+ ```
+ curl -i -X PATCH -H "Authorization: Basic YWRtaW4xOnBhc3N3b3JkMTIzNDU2Nzg=" -H "Content-Type: application/json" -d '{"active":false}' https://localhost:4003/user/cZFxFfNT --insecure
+
+ HTTP/1.1 204 No Content
+ server: Cowboy
+ date: Wed, 05 Sep 2018 13:38:32 GMT
+ content-length: 0
+ cache-control: max-age=0, private, must-revalidate
+ ```
+
## Blacklist Token Endpoint
This Endpoint is used when we want to ban a single JWT Token (not the entire user) and that will convert that Token invalid. This Endpoint is only called by Admins.
diff --git a/lib/poa_backend/auth/router.ex b/lib/poa_backend/auth/router.ex
index 35800de..75d6d39 100644
--- a/lib/poa_backend/auth/router.ex
+++ b/lib/poa_backend/auth/router.ex
@@ -107,6 +107,31 @@ defmodule POABackend.Auth.Router do
end
end
+ patch "/user/:user_name" 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),
+ true <- is_boolean(conn.params["active"])
+ do
+ case Auth.get_user(user_name) do
+ nil -> send_resp(conn, 404, "")
+ user ->
+ set_active_user(user, conn.params["active"])
+ send_resp(conn, 204, "")
+ end
+ else
+ false ->
+ conn
+ |> send_resp(422, "")
+ |> halt
+ _error ->
+ conn
+ |> send_resp(401, "")
+ |> halt
+ end
+ end
+
post "/blacklist/user" do
with {"authorization", "Basic " <> base64} <- List.keyfind(conn.req_headers, "authorization", 0),
{:ok, decoded64} <- Base.decode64(base64),
@@ -163,4 +188,13 @@ defmodule POABackend.Auth.Router do
send_resp(conn, 404, "")
end
+ defp set_active_user(user, true) do
+ Auth.activate_user(user)
+ :ok
+ end
+ defp set_active_user(user, false) do
+ Auth.deactivate_user(user)
+ :ok
+ end
+
end
\ No newline at end of file
diff --git a/lib/poa_backend/custom_handler/rest/plugs/content_type.ex b/lib/poa_backend/custom_handler/rest/plugs/content_type.ex
index 9d8e83c..0150f09 100644
--- a/lib/poa_backend/custom_handler/rest/plugs/content_type.ex
+++ b/lib/poa_backend/custom_handler/rest/plugs/content_type.ex
@@ -9,7 +9,7 @@ defmodule POABackend.CustomHandler.REST.Plugs.ContentType do
accepted_content_type
end
- def call(%Conn{method: method} = conn, accepted_content_type) when method in ["POST", "PUT"] do
+ def call(%Conn{method: method} = conn, accepted_content_type) when method in ["POST", "PUT", "PATCH"] do
import Plug.Conn
with {"content-type", content_type} <- List.keyfind(conn.req_headers, "content-type", 0),
diff --git a/test/auth/api_test.exs b/test/auth/api_test.exs
index 99de1f4..6d4e68f 100644
--- a/test/auth/api_test.exs
+++ b/test/auth/api_test.exs
@@ -387,6 +387,198 @@ defmodule Auth.APITest do
assert {401, :nobody} == delete(url <> "/ferigis", headers)
end
+ test "updating user [JSON]" do
+ url = @base_url <> "/user"
+ mime_type = "application/json"
+ headers = [
+ {"Content-Type", mime_type},
+ {"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
+ ]
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+
+ result =
+ %{}
+ |> Map.put(:active, false)
+ |> Poison.encode!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {204, :nobody} == result
+
+ {200, [initial_user]} = get(url, headers)
+
+ refute initial_user["active"]
+
+ result =
+ %{}
+ |> Map.put(:active, true)
+ |> Poison.encode!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {204, :nobody} == result
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+ end
+
+ test "updating user [MSGPACK]" do
+ url = @base_url <> "/user"
+ mime_type = "application/msgpack"
+ headers = [
+ {"Content-Type", mime_type},
+ {"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
+ ]
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+
+ result =
+ %{}
+ |> Map.put(:active, false)
+ |> Msgpax.pack!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {204, :nobody} == result
+
+ {200, [initial_user]} = get(url, headers)
+
+ refute initial_user["active"]
+
+ result =
+ %{}
+ |> Map.put(:active, true)
+ |> Msgpax.pack!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {204, :nobody} == result
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+ end
+
+ test "updating user with wrong active value (not boolean) [JSON]" do
+ url = @base_url <> "/user"
+ mime_type = "application/json"
+ headers = [
+ {"Content-Type", mime_type},
+ {"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
+ ]
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+
+ result =
+ %{}
+ |> Map.put(:active, "wrong value")
+ |> Poison.encode!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {422, :nobody} == result
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+ end
+
+ test "updating user with wrong active value (not boolean) [MSGPACK]" do
+ url = @base_url <> "/user"
+ mime_type = "application/msgpack"
+ headers = [
+ {"Content-Type", mime_type},
+ {"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
+ ]
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+
+ result =
+ %{}
+ |> Map.put(:active, "wrong value")
+ |> Msgpax.pack!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {422, :nobody} == result
+
+ {200, [initial_user]} = get(url, headers)
+
+ assert initial_user["active"]
+ end
+
+ test "updating 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 =
+ %{}
+ |> Map.put(:active, false)
+ |> Poison.encode!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {401, :nobody} == result
+ end
+
+ test "updating 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 =
+ %{}
+ |> Map.put(:active, false)
+ |> Msgpax.pack!
+ |> patch(url <> "/ferigis", headers)
+
+ assert {401, :nobody} == result
+ end
+
+ test "updating user who doesn't exist [JSON]" do
+ url = @base_url <> "/user"
+ mime_type = "application/json"
+ headers = [
+ {"Content-Type", mime_type},
+ {"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
+ ]
+
+ result =
+ %{}
+ |> Map.put(:active, true)
+ |> Poison.encode!
+ |> patch(url <> "/unnexistinguser", headers)
+
+ assert {404, :nobody} == result
+ end
+
+ test "updating user who doesn't exist [MSGPACK]" do
+ url = @base_url <> "/user"
+ mime_type = "application/msgpack"
+ headers = [
+ {"Content-Type", mime_type},
+ {"authorization", "Basic " <> Base.encode64(@admin <> ":" <> @admin_pwd)}
+ ]
+
+ result =
+ %{}
+ |> Map.put(:active, true)
+ |> Msgpax.pack!
+ |> patch(url <> "/unnexistinguser", headers)
+
+ assert {404, :nobody} == result
+ end
+
# ----------------------------------------
# /blacklist/user Endpoint Tests
# ----------------------------------------
@@ -745,4 +937,18 @@ defmodule Auth.APITest do
{response.status_code, body}
end
+ defp patch(data, url, headers) do
+ options = [ssl: [{:versions, [:'tlsv1.2']}], recv_timeout: 500]
+ {:ok, response} = HTTPoison.patch(url, data, headers, options)
+
+ body = case response.body do
+ "" ->
+ :nobody
+ _ ->
+ {:ok, body} = Poison.decode(response.body)
+ body
+ end
+
+ {response.status_code, body}
+ end
end