]> Entropealabs - wampex_router.git/commitdiff
add authorization
authorChristopher <chris@entropealabs.com>
Thu, 26 Mar 2020 02:19:09 +0000 (21:19 -0500)
committerChristopher <chris@entropealabs.com>
Thu, 26 Mar 2020 02:19:09 +0000 (21:19 -0500)
lib/router/authentication.ex
lib/router/authorization.ex [new file with mode: 0644]
lib/router/session.ex

index ae31386d57611d391825dc35427725718506dc65..042c9760900b871e5d221efa175c222e3a086032 100644 (file)
@@ -13,5 +13,5 @@ defmodule Wampex.Router.Authentication do
               realm :: String.t(),
               authid :: String.t(),
               challenge :: map()
-            ) :: boolean()
+            ) :: {boolean(), any()}
 end
diff --git a/lib/router/authorization.ex b/lib/router/authorization.ex
new file mode 100644 (file)
index 0000000..cde9f26
--- /dev/null
@@ -0,0 +1,7 @@
+defmodule Wampex.Router.Authorization do
+  @moduledoc false
+
+  @type access_type :: :publish | :subscribe | :register | :call
+
+  @callback authorized?(type :: access_type(), uri :: String.t(), data :: any()) :: true | false
+end
index a843e2c2ea9443aeec6badb400482a70d21c82ff..b512c64c1efd3c611aba43af2ada33ace9e9a472 100644 (file)
@@ -38,7 +38,7 @@ defmodule Wampex.Router.Session do
     :realm,
     :name,
     :goodbye,
-    :peer_information,
+    :peer,
     :challenge,
     :authentication_module,
     :authorization_module,
@@ -190,8 +190,7 @@ defmodule Wampex.Router.Session do
            data
            | challenge: challenge,
              hello_received: true,
-             realm: realm,
-             peer_information: options
+             realm: realm
          }
      }, [{:next_event, :internal, :transition}] ++ actions}
   end
@@ -216,9 +215,9 @@ defmodule Wampex.Router.Session do
       ) do
     info = auth.parse_challenge(challenge)
 
-    {actions, proxy} = maybe_welcome({auth, session_id, sig, realm, name, challenge, info, tt, t})
+    {actions, proxy, peer} = maybe_welcome({auth, session_id, sig, realm, name, challenge, info, tt, t})
 
-    {:ok, %SL{sl | data: %Sess{sl.data | proxy: proxy}}, actions}
+    {:ok, %SL{sl | data: %Sess{sl.data | peer: peer, proxy: proxy}}, actions}
   end
 
   @impl true
@@ -255,19 +254,28 @@ defmodule Wampex.Router.Session do
               transport_pid: t,
               subscriptions: subs,
               realm: realm,
+              authorization_module: am,
+              peer: peer,
               subscribe: %Subscribe{request_id: ri, options: opts, topic: topic},
               db: db
             } = data
         } = sl
       ) do
-    id = RealmSession.get_id()
+    {data, actions} =
+      case is_authorized?(am, peer, :subscribe, topic) do
+        true ->
+          id = RealmSession.get_id()
+          wc = RealmSession.subscribe(db, realm, topic, {id, {self(), Node.self()}}, opts)
+          send_to_peer(Broker.subscribed(%Subscribed{request_id: ri, subscription_id: id}), tt, t)
 
-    wc = RealmSession.subscribe(db, realm, topic, {id, {self(), Node.self()}}, opts)
+          {%SL{sl | data: %Sess{data | subscriptions: [{id, topic, wc} | subs]}},
+           [{:next_event, :internal, :transition}]}
 
-    send_to_peer(Broker.subscribed(%Subscribed{request_id: ri, subscription_id: id}), tt, t)
+        false ->
+          {%SL{sl | data: %Sess{data | error: "wamp.error.not_authorized"}}, [{:next_event, :internal, :transition}]}
+      end
 
-    {:ok, %SL{sl | data: %Sess{data | subscriptions: [{id, topic, wc} | subs]}},
-     [{:next_event, :internal, :transition}]}
+    {:ok, data, actions}
   end
 
   @impl true
@@ -289,7 +297,6 @@ defmodule Wampex.Router.Session do
     subs = RealmSession.unsubscribe(db, realm, {subscription_id, {self(), Node.self()}}, subs)
 
     send_to_peer(Broker.unsubscribed(%Unsubscribed{request_id: rid}), tt, t)
-
     {:ok, %SL{sl | data: %Sess{sl.data | subscriptions: subs}}, [{:next_event, :internal, :transition}]}
   end
 
@@ -299,42 +306,54 @@ defmodule Wampex.Router.Session do
         _,
         @publish,
         %SL{
-          data: %Sess{
-            proxy: proxy,
-            realm: realm,
-            transport: tt,
-            transport_pid: t,
-            db: db,
-            publish: %Publish{request_id: rid, options: opts, topic: topic, arg_list: arg_l, arg_kw: arg_kw}
-          }
+          data:
+            %Sess{
+              proxy: proxy,
+              realm: realm,
+              transport: tt,
+              transport_pid: t,
+              db: db,
+              authorization_module: am,
+              peer: peer,
+              publish: %Publish{request_id: rid, options: opts, topic: topic, arg_list: arg_l, arg_kw: arg_kw}
+            } = data
         } = sl
       ) do
-    pub_id = RealmSession.get_id()
-
-    subs = RealmSession.subscriptions(db, realm, topic)
-
-    Enum.each(subs, fn {id, {pid, node}} ->
-      send(
-        {proxy, node},
-        {%Event{
-           subscription_id: id,
-           publication_id: pub_id,
-           arg_list: arg_l,
-           arg_kw: arg_kw,
-           details: opts
-         }, pid}
-      )
-    end)
+    {data, actions} =
+      case is_authorized?(am, peer, :publish, topic) do
+        true ->
+          pub_id = RealmSession.get_id()
+
+          subs = RealmSession.subscriptions(db, realm, topic)
+
+          Enum.each(subs, fn {id, {pid, node}} ->
+            send(
+              {proxy, node},
+              {%Event{
+                 subscription_id: id,
+                 publication_id: pub_id,
+                 arg_list: arg_l,
+                 arg_kw: arg_kw,
+                 details: opts
+               }, pid}
+            )
+          end)
 
-    case opts do
-      %{acknowledge: true} ->
-        send_to_peer(Broker.published(%Published{request_id: rid, publication_id: pub_id}), tt, t)
+          case opts do
+            %{acknowledge: true} ->
+              send_to_peer(Broker.published(%Published{request_id: rid, publication_id: pub_id}), tt, t)
 
-      %{} ->
-        :noop
-    end
+            %{} ->
+              :noop
+          end
+
+          {sl, [{:next_event, :internal, :transition}]}
+
+        false ->
+          {%SL{sl | data: %Sess{data | error: "wamp.error.not_authorized"}}, [{:next_event, :internal, :transition}]}
+      end
 
-    {:ok, sl, [{:next_event, :internal, :transition}]}
+    {:ok, data, actions}
   end
 
   @impl true
@@ -373,17 +392,28 @@ defmodule Wampex.Router.Session do
               registrations: regs,
               db: db,
               realm: realm,
+              authorization_module: am,
+              peer: peer,
               register: %Register{request_id: rid, procedure: procedure}
             } = data
         } = sl
       ) do
-    id = RealmSession.get_id()
-    RealmSession.register(db, realm, procedure, {id, {self(), Node.self()}})
-    regd = %Registered{request_id: rid, registration_id: id}
-    send_to_peer(Dealer.registered(regd), tt, t)
+    {data, actions} =
+      case is_authorized?(am, peer, :register, procedure) do
+        true ->
+          id = RealmSession.get_id()
+          RealmSession.register(db, realm, procedure, {id, {self(), Node.self()}})
+          regd = %Registered{request_id: rid, registration_id: id}
+          send_to_peer(Dealer.registered(regd), tt, t)
+
+          {%SL{sl | data: %Sess{data | registrations: [{id, procedure} | regs]}},
+           [{:next_event, :internal, :transition}]}
+
+        false ->
+          {%SL{sl | data: %Sess{data | error: "wamp.error.not_authorized"}}, [{:next_event, :internal, :transition}]}
+      end
 
-    {:ok, %SL{sl | data: %Sess{data | registrations: [{id, procedure} | regs]}},
-     [{:next_event, :internal, :transition}]}
+    {:ok, data, actions}
   end
 
   @impl true
@@ -400,66 +430,74 @@ defmodule Wampex.Router.Session do
               transport_pid: t,
               realm: realm,
               request_id: ri,
+              authorization_module: am,
+              peer: peer,
               call: %Call{request_id: call_id, options: opts, procedure: proc, arg_list: al, arg_kw: akw}
             } = data
         } = sl
       ) do
-    data =
-      with {callees, index} <- RealmSession.callees(db, realm, proc),
-           {id, {pid, node}} <- get_live_callee(proxy, callees, index, 3) do
-        req_id = RealmSession.get_request_id(ri)
-        opts = Map.put(opts, "procedure", proc)
-
-        send(
-          {proxy, node},
-          {
-            {
-              call_id,
-              %Invocation{
-                request_id: req_id,
-                registration_id: id,
-                details: opts,
-                arg_list: al,
-                arg_kw: akw
-              },
-              {self(), Node.self()}
-            },
-            pid
-          }
-        )
+    {data, actions} =
+      case is_authorized?(am, peer, :call, proc) do
+        true ->
+          with {callees, index} <- RealmSession.callees(db, realm, proc),
+               {id, {pid, node}} <- get_live_callee(proxy, callees, index, 3) do
+            req_id = RealmSession.get_request_id(ri)
+            opts = Map.put(opts, "procedure", proc)
+
+            send(
+              {proxy, node},
+              {
+                {
+                  call_id,
+                  %Invocation{
+                    request_id: req_id,
+                    registration_id: id,
+                    details: opts,
+                    arg_list: al,
+                    arg_kw: akw
+                  },
+                  {self(), Node.self()}
+                },
+                pid
+              }
+            )
+
+            RealmSession.round_robin(db, realm, proc, length(callees))
+
+            {%SL{sl | data: %Sess{data | request_id: req_id}}, [{:next_event, :internal, :transition}]}
+          else
+            {:error, :no_live_callees} ->
+              send_to_peer(
+                Caller.call_error(%Error{
+                  request_id: call_id,
+                  error: "wamp.error.no_callees",
+                  details: %{procedure: proc}
+                }),
+                tt,
+                t
+              )
+
+              {sl, [{:next_event, :internal, :transition}]}
+
+            :not_found ->
+              send_to_peer(
+                Caller.call_error(%Error{
+                  request_id: call_id,
+                  error: "wamp.error.no_registration",
+                  details: %{procedure: proc}
+                }),
+                tt,
+                t
+              )
+
+              {sl, [{:next_event, :internal, :transition}]}
+          end
 
-        RealmSession.round_robin(db, realm, proc, length(callees))
-
-        %SL{sl | data: %Sess{data | request_id: req_id}}
-      else
-        {:error, :no_live_callees} ->
-          send_to_peer(
-            Caller.call_error(%Error{
-              request_id: call_id,
-              error: "wamp.error.no_callees",
-              details: %{procedure: proc}
-            }),
-            tt,
-            t
-          )
-
-          sl
-
-        :not_found ->
-          send_to_peer(
-            Caller.call_error(%Error{
-              request_id: call_id,
-              error: "wamp.error.no_registration",
-              details: %{procedure: proc}
-            }),
-            tt,
-            t
-          )
-
-          sl
+        false ->
+          {%SL{sl | data: %Sess{data | error: "wamp.error.not_authorized"}}, [{:next_event, :internal, :transition}]}
       end
 
-    {:ok, data, [{:next_event, :internal, :transition}]}
+    {:ok, data, actions}
   end
 
   @impl true
@@ -601,7 +639,7 @@ defmodule Wampex.Router.Session do
          {auth, session_id, sig, realm, name, challenge, {authid, authrole, authmethod, authprovider}, tt, t}
        ) do
     case auth.authenticate(sig, realm, authid, challenge) do
-      true ->
+      {true, peer} ->
         proxy = Realms.start_realm(Router.realms_name(name), realm)
 
         send_to_peer(
@@ -620,10 +658,10 @@ defmodule Wampex.Router.Session do
           t
         )
 
-        {[{:next_event, :internal, :transition}], proxy}
+        {[{:next_event, :internal, :transition}], proxy, peer}
 
-      false ->
-        {[{:next_event, :internal, :transition}, {:next_event, :internal, :abort}], nil}
+      {false, peer} ->
+        {[{:next_event, :internal, :transition}, {:next_event, :internal, :abort}], nil, peer}
     end
   end
 
@@ -686,6 +724,10 @@ defmodule Wampex.Router.Session do
 
   defp maybe_update_response(data, resp), do: {data, resp}
 
+  def is_authorized?(am, peer, type, uri) do
+    am.authorized?(type, uri, peer)
+  end
+
   defp remove_nil_values(message) do
     message =
       case Enum.reverse(message) do