use Mix.Config
+
+import_config "#{Mix.env()}.exs"
--- /dev/null
+use Mix.Config
--- /dev/null
+use Mix.Config
--- /dev/null
+use Mix.Config
+
+config :wampex_router,
+ topologies: [
+ kv: [
+ strategy: Cluster.Strategy.Epmd,
+ config: [
+ hosts: []
+ ],
+ connect: {:net_kernel, :connect_node, []},
+ disconnect: {:erlang, :disconnect_node, []},
+ list_nodes: {:erlang, :nodes, [:connected]}
+ ]
+ ]
alias Wampex.Client.Session, as: Sess
alias Wampex.Roles.{Callee, Subscriber}
- alias Wampex.Roles.Callee.Yield
- alias Wampex.Roles.Callee.Register
+ alias Wampex.Roles.Callee.{Register, Yield}
alias Wampex.Roles.Caller
alias Wampex.Roles.Caller.Call
alias Wampex.Roles.Dealer.Result
{:msgpack, "~> 0.7.0"},
{:pbkdf2, "~> 2.0"},
{:states_language, "~> 0.2"},
- # {:wampex, path: "../wampex"},
{:wampex,
git: "https://gitlab.com/entropealabs/wampex.git",
- tag: "7d656d9748cb0e4d08c625d87e315839afecb4b2"},
+ tag: "ecba713117f1e048829be79f19373952638c6ece"},
+ {:wampex_router,
+ git: "https://gitlab.com/entropealabs/wampex_router.git", tag: "master", only: [:test]},
{:websockex, "~> 0.4.2"}
]
end
%{
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"},
+ "cluster_kv": {:git, "https://gitlab.com/entropealabs/cluster_kv.git", "d3bb958de67ef22304f24641661261a1c2df684d", [tag: "d3bb958de67ef22304f24641661261a1c2df684d"]},
"conv_case": {:hex, :conv_case, "0.2.2", "5a98b74ab8f7ddbad670e5c7bb39ff280e60699aa3b25c7062ceccf48137433c", [:mix], [], "hexpm", "561c550ab6d55b2a4d4c14449e58c9957798613eb26ea182e14a962965377bca"},
"credo": {:hex, :credo, "1.3.1", "082e8d9268a489becf8e7aa75671a7b9088b1277cd6c1b13f40a55554b3f5126", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "0da816ed52fa520b9ea0e5d18a0d3ca269e0bd410b1174d88d8abd94be6cce3c"},
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm", "6c32a70ed5d452c6650916555b1f96c79af5fc4bf286997f8b15f213de786f73"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"msgpack": {:hex, :msgpack, "0.7.0", "128ae0a2227c7e7a2847c0f0f73551c268464f8c1ee96bffb920bc0a5712b295", [:rebar3], [], "hexpm", "4649353da003e6f438d105e4b1e0f17757f6f5ec8687a6f30875ff3ac4ce2a51"},
+ "msgpax": {:hex, :msgpax, "2.2.4", "7b3790ef684089076b63c0f08c2f4b079c6311daeb006b69e4ed2bf67518291e", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "b351b6d992d79624a8430a99d21a41b36b1b90edf84326a294e9f4a2de11f089"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"pbkdf2": {:hex, :pbkdf2, "2.0.0", "11c23279fded5c0027ab3996cfae77805521d7ef4babde2bd7ec04a9086cf499", [:rebar3], [], "hexpm", "1e793ce6fdb0576613115714deae9dfc1d1537eaba74f07efb36de139774488d"},
"states_language": {:hex, :states_language, "0.2.8", "f9dfd3c0bd9a9d7bda25ef315f2d90944cd6b2022a7f3c403deb1d4ec451825e", [:mix], [{:elixpath, "~> 0.1.0", [hex: :elixpath, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:json_xema, "~> 0.4.0", [hex: :json_xema, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:xema, "~> 0.11.0", [hex: :xema, repo: "hexpm", optional: false]}], "hexpm", "a5231691e7cb37fe32dc7de54c2dc86d1d60e84c4f0379f3246e55be2a85ec78"},
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
- "wampex": {:git, "https://gitlab.com/entropealabs/wampex.git", "61d834a784f5f14ec90508cf7556a5ebaec113c3", [tag: "61d834a784f5f14ec90508cf7556a5ebaec113c3"]},
+ "wampex": {:git, "https://gitlab.com/entropealabs/wampex.git", "ecba713117f1e048829be79f19373952638c6ece", [tag: "ecba713117f1e048829be79f19373952638c6ece"]},
+ "wampex_router": {:git, "https://gitlab.com/entropealabs/wampex_router.git", "0dd5879951be976e533cdae554e581202d557c17", [tag: "master"]},
"websockex": {:hex, :websockex, "0.4.2", "9a3b7dc25655517ecd3f8ff7109a77fce94956096b942836cdcfbc7c86603ecc", [:mix], [], "hexpm", "803cd76e91544b56f0e655e36790be797fa6436db9224f7c303db9b9df2a3df4"},
"xema": {:hex, :xema, "0.11.0", "7b5118418633cffc27092110d02d4faeea938149dd3f6c64299e41e747067e80", [:mix], [{:conv_case, "~> 0.2.2", [hex: :conv_case, repo: "hexpm", optional: false]}, {:decimal, "~> 1.7", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "51491c9a953d65069d4b30aa2f70bc45ff99fd1bc3345bc72ce4e644d01ea14e"},
}
--- /dev/null
+defmodule Wampex.Router.AuthenticationImpl do
+ @moduledoc false
+ @behaviour Wampex.Router.Authentication
+ require Logger
+
+ alias Wampex.Crypto
+ alias Wampex.Serializers.JSON
+
+ @wampcra "wampcra"
+ @auth_provider "userdb"
+ @auth_role "user"
+ @auth_password "bnASR5qF9y8k/sHF6S+NneCOhvVI0zFkvoKQpc2F+hA="
+ @salt "test"
+ @keylen 32
+ @iterations 10
+
+ @impl true
+ def authenticate?(methods) do
+ can_auth(methods)
+ end
+
+ @impl true
+ def method, do: @wampcra
+
+ @impl true
+ def challenge(_realm, authid, session_id) do
+ now = DateTime.to_iso8601(DateTime.utc_now())
+
+ %{
+ challenge:
+ JSON.serialize!(%{
+ nonce: Crypto.random_string(@keylen),
+ authprovider: @auth_provider,
+ authid: authid,
+ timestamp: now,
+ authrole: @auth_role,
+ authmethod: @wampcra,
+ session: session_id
+ }),
+ salt: @salt,
+ keylen: @keylen,
+ iterations: @iterations
+ }
+ end
+
+ @impl true
+ def parse_challenge(challenge) do
+ ch = JSON.deserialize!(challenge.challenge)
+
+ {get_in(ch, ["authid"]), get_in(ch, ["authrole"]), get_in(ch, ["authmethod"]), get_in(ch, ["authprovider"])}
+ end
+
+ @impl true
+ def authenticate(signature, realm, authid, %{
+ challenge: challenge
+ }) do
+ authed =
+ authid
+ |> get_secret(realm)
+ |> Crypto.hash_challenge(challenge)
+ |> :pbkdf2.compare_secure(signature)
+
+ {authed, %{}}
+ end
+
+ defp get_secret(_authid, _uri), do: Crypto.pbkdf2(@auth_password, @salt, @iterations, @keylen)
+
+ defp can_auth([]), do: false
+ defp can_auth([@wampcra | _]), do: true
+ defp can_auth([_ | t]), do: can_auth(t)
+end
--- /dev/null
+defmodule Wampex.Router.AuthorizationImpl do
+ @moduledoc false
+ @behaviour Wampex.Router.Authorization
+
+ @impl true
+ def authorized?(_, _, _), do: true
+end
use GenServer
require Logger
alias Wampex.Client
- alias Wampex.Roles.Subscriber
- alias Subscriber.Subscribe
+ alias Wampex.Roles.Subscriber.Subscribe
def start_link(test, name, topic) do
GenServer.start_link(__MODULE__, {test, name, topic})
alias Wampex.Roles.Dealer.{Invocation, Result}
alias Wampex.Roles.Peer.{Error, Hello}
alias Wampex.Roles.Publisher.Publish
+ alias Wampex.Router
+ alias Wampex.Router.AuthenticationImpl
+ alias Wampex.Router.AuthorizationImpl
require Logger
- @url "ws://localhost:4000/ws"
+ @url "ws://localhost:5999/ws"
@authid "admin"
@auth_password "test1234"
@realm_uri "admin"
@session %Session{url: @url, realm: @realm, roles: @roles}
+ setup_all do
+ topologies = Application.get_env(:wampex_router, :topologies)
+
+ [
+ server:
+ Router.start_link(
+ name: TestRouter,
+ port: 5999,
+ topologies: topologies,
+ replicas: 1,
+ quorum: 1,
+ authentication_module: AuthenticationImpl,
+ authorization_module: AuthorizationImpl
+ )
+ ]
+ end
+
@tag :client
test "callee registration" do
name = TestCalleeRegistration
- Client.start_link(name: name, session: @session)
+ Client.start_link(name: name, session: @session, reconnect: false)
TestCallee.start_link(self(), name, @device)
assert_receive {:registered, id}
end
test "abort" do
Process.flag(:trap_exit, true)
callee_name = TestAbort
- {:ok, pid} = Client.start_link(name: callee_name, session: @session)
- Client.cast(callee_name, Peer.hello(%Hello{realm: "test", roles: [Callee]}))
- assert_receive {:EXIT, ^pid, :shutdown}, 1000
+ {:ok, _pid} = Client.start_link(name: callee_name, session: @session, reconnect: false)
+
+ try do
+ Client.cast(callee_name, Peer.hello(%Hello{realm: "test", roles: [Callee]}))
+ catch
+ :exit, er ->
+ assert {:normal, _} = er
+ end
end
@tag :client
test "caller receives error when calling unknown procedure" do
caller_name = TestExistCaller
- Client.start_link(name: caller_name, session: @session)
+ Client.start_link(name: caller_name, session: @session, reconnect: false)
assert %Error{error: "wamp.error.no_registration"} =
Client.call(
@tag :client
test "admin callee is invoked and responds and caller gets result" do
caller_name = TestAdminCaller
- Client.start_link(name: caller_name, session: @session)
+ Client.start_link(name: caller_name, session: @session, reconnect: false)
assert %Result{arg_kw: %{"authid" => "chris"}} =
Client.call(
@tag :client
test "admin callee is invoked and responds with error" do
caller_name = TestAdminErrorCaller
- Client.start_link(name: caller_name, session: @session)
+ Client.start_link(name: caller_name, session: @session, reconnect: false)
assert %Error{error: "error"} =
Client.call(
@tag :client
test "callee is invoked and responds and caller gets result" do
callee_name = TestCalleeRespond
- Client.start_link(name: callee_name, session: @session)
+ Client.start_link(name: callee_name, session: @session, reconnect: false)
TestCallee.start_link(self(), callee_name, @device)
assert_receive {_, _}
caller_name = TestCaller
- Client.start_link(name: caller_name, session: @session)
+ Client.start_link(name: caller_name, session: @session, reconnect: false)
%Result{arg_list: ["ok"], arg_kw: %{"color" => "#FFFFFF"}} =
Client.call(
@tag :client
test "subscriber registration" do
name = TestSubscriberRegister
- Client.start_link(name: name, session: @session)
+ Client.start_link(name: name, session: @session, reconnect: false)
TestSubscriber.start_link(self(), name, "com.data.temp")
assert_receive {:subscribed, id}
end
@tag :client
test "subscriber receives events from publisher" do
name = TestSubscriberEvents
- Client.start_link(name: name, session: @session)
+ Client.start_link(name: name, session: @session, reconnect: false)
TestSubscriber.start_link(self(), name, "com.data.test.temp")
assert_receive {:subscribed, id}
- Client.start_link(name: TestPublisher, session: @session)
+ Client.start_link(name: TestPublisher, session: @session, reconnect: false)
Client.publish(
TestPublisher,