[ARVADOS] updated: cb52a672642bdec7c6a97868a68bbb9b8daa0efb

git at public.curoverse.com git at public.curoverse.com
Tue Apr 22 15:20:00 EDT 2014


Summary of changes:
 apps/workbench/app/views/websocket/index.html.erb  |    5 +-
 .../api/app/controllers/application_controller.rb  |   58 ---------------
 services/api/app/middlewares/arvados_api_token.rb  |   52 ++++++++++++++
 services/api/app/middlewares/rack_socket.rb        |   48 +------------
 services/api/app/models/arvados_model.rb           |    2 +-
 services/api/config/initializers/authorization.rb  |    5 ++
 services/api/config/initializers/eventbus.rb       |    4 +-
 services/api/lib/eventbus.rb                       |   75 ++++++++++++++++++++
 8 files changed, 141 insertions(+), 108 deletions(-)
 create mode 100644 services/api/app/middlewares/arvados_api_token.rb
 create mode 100644 services/api/config/initializers/authorization.rb
 create mode 100644 services/api/lib/eventbus.rb

       via  cb52a672642bdec7c6a97868a68bbb9b8daa0efb (commit)
       via  d07a96a0f0c11b98ecc927f0b3e0b052f8ef99f7 (commit)
       via  e484a466d78c87114779b596d6ecd79f22088ee2 (commit)
      from  aa920f1659aa830861c196617fe664f35b5c12ef (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit cb52a672642bdec7c6a97868a68bbb9b8daa0efb
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Tue Apr 22 15:19:51 2014 -0400

    Added permission checking to event bus so that it only report changes for
    objects that the user has current read permission.

diff --git a/services/api/lib/eventbus.rb b/services/api/lib/eventbus.rb
index 30b400c..26674b7 100644
--- a/services/api/lib/eventbus.rb
+++ b/services/api/lib/eventbus.rb
@@ -2,6 +2,13 @@ require 'eventmachine'
 require 'oj'
 require 'faye/websocket'
 
+module Faye
+  class WebSocket
+    attr_accessor :user
+    attr_accessor :last_log_id
+  end
+end
+
 class EventBus
   include CurrentApiClient
 
@@ -18,9 +25,16 @@ class EventBus
       return
     end
 
+    ws.user = current_user
+
     sub = @channel.subscribe do |msg|
       Log.where(id: msg.to_i).each do |l|
-        ws.send(l.as_api_response.to_json)
+        if rsc = ArvadosModel::resource_class_for_uuid(l.object_uuid)
+          rsc.readable_by(ws.user).where(uuid: l.object_uuid).each do
+            ws.send(l.as_api_response.to_json)
+          end
+        end
+        ws.last_log_id = msg.to_i
       end
     end
 

commit d07a96a0f0c11b98ecc927f0b3e0b052f8ef99f7
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Tue Apr 22 14:24:03 2014 -0400

    Moves API token authentication from ApplicationController into ArvadosApiToken Rack middleware.
    Rearranges rack middleware stack a bit to accomodate.

diff --git a/apps/workbench/app/views/websocket/index.html.erb b/apps/workbench/app/views/websocket/index.html.erb
index e1fca78..425ddd4 100644
--- a/apps/workbench/app/views/websocket/index.html.erb
+++ b/apps/workbench/app/views/websocket/index.html.erb
@@ -15,12 +15,13 @@
 <script>
 $(function() {
 putStuffThere = function (content) {
-  $("#PutStuffHere").append(content["message"] + "<br>");
+  $("#PutStuffHere").append(content + "<br>");
 };
 
 var dispatcher = new WebSocket('ws://localhost:3001/websocket?api_token=<%= Thread.current[:arvados_api_token] %>');
 dispatcher.onmessage = function(event) {
-  putStuffThere(JSON.parse(event.data));
+  //putStuffThere(JSON.parse(event.data));
+  putStuffThere(event.data);
 };
 
 sendStuff = function () {
diff --git a/services/api/app/controllers/application_controller.rb b/services/api/app/controllers/application_controller.rb
index 4b13fca..033eccd 100644
--- a/services/api/app/controllers/application_controller.rb
+++ b/services/api/app/controllers/application_controller.rb
@@ -4,7 +4,6 @@ class ApplicationController < ActionController::Base
 
   respond_to :json
   protect_from_forgery
-  around_filter :thread_with_auth_info, :except => [:render_error, :render_not_found]
 
   before_filter :remote_ip
   before_filter :require_auth_scope_all, :except => :render_not_found
@@ -330,63 +329,6 @@ class ApplicationController < ActionController::Base
     end
   end
 
-  def thread_with_auth_info
-    Thread.current[:request_starttime] = Time.now
-    Thread.current[:api_url_base] = root_url.sub(/\/$/,'') + '/arvados/v1'
-    begin
-      user = nil
-      api_client = nil
-      api_client_auth = nil
-      supplied_token =
-        params[:api_token] ||
-        params[:oauth_token] ||
-        request.headers["Authorization"].andand.match(/OAuth2 ([a-z0-9]+)/).andand[1]
-      if supplied_token
-        api_client_auth = ApiClientAuthorization.
-          includes(:api_client, :user).
-          where('api_token=? and (expires_at is null or expires_at > CURRENT_TIMESTAMP)', supplied_token).
-          first
-        if api_client_auth.andand.user
-          session[:user_id] = api_client_auth.user.id
-          session[:api_client_uuid] = api_client_auth.api_client.andand.uuid
-          session[:api_client_authorization_id] = api_client_auth.id
-          user = api_client_auth.user
-          api_client = api_client_auth.api_client
-        else
-          # Token seems valid, but points to a non-existent (deleted?) user.
-          api_client_auth = nil
-        end
-      elsif session[:user_id]
-        user = User.find(session[:user_id]) rescue nil
-        api_client = ApiClient.
-          where('uuid=?',session[:api_client_uuid]).
-          first rescue nil
-        if session[:api_client_authorization_id] then
-          api_client_auth = ApiClientAuthorization.
-            find session[:api_client_authorization_id]
-        end
-      end
-      Thread.current[:api_client_ip_address] = remote_ip
-      Thread.current[:api_client_authorization] = api_client_auth
-      Thread.current[:api_client_uuid] = api_client.andand.uuid
-      Thread.current[:api_client] = api_client
-      Thread.current[:user] = user
-      if api_client_auth
-        api_client_auth.last_used_at = Time.now
-        api_client_auth.last_used_by_ip_address = remote_ip
-        api_client_auth.save validate: false
-      end
-      yield
-    ensure
-      Thread.current[:api_client_ip_address] = nil
-      Thread.current[:api_client_authorization] = nil
-      Thread.current[:api_client_uuid] = nil
-      Thread.current[:api_client] = nil
-      Thread.current[:user] = nil
-    end
-  end
-  # /Authentication
-
   def model_class
     controller_name.classify.constantize
   end
diff --git a/services/api/app/middlewares/arvados_api_token.rb b/services/api/app/middlewares/arvados_api_token.rb
new file mode 100644
index 0000000..fac1916
--- /dev/null
+++ b/services/api/app/middlewares/arvados_api_token.rb
@@ -0,0 +1,52 @@
+class ArvadosApiToken
+  def initialize(app = nil, options = nil)
+    @app = app if app.respond_to?(:call)
+  end
+
+  def call env
+    # first, clean up just in case
+    Thread.current[:api_client_ip_address] = nil
+    Thread.current[:api_client_authorization] = nil
+    Thread.current[:api_client_uuid] = nil
+    Thread.current[:api_client] = nil
+    Thread.current[:user] = nil
+
+    request = Rack::Request.new(env)
+    params = request.params
+    remote_ip = env["action_dispatch.remote_ip"]
+
+    Thread.current[:request_starttime] = Time.now
+    user = nil
+    api_client = nil
+    api_client_auth = nil
+    supplied_token =
+      params["api_token"] ||
+      params["oauth_token"] ||
+      env["HTTP_AUTHORIZATION"].andand.match(/OAuth2 ([a-z0-9]+)/).andand[1]
+    if supplied_token
+      api_client_auth = ApiClientAuthorization.
+        includes(:api_client, :user).
+        where('api_token=? and (expires_at is null or expires_at > CURRENT_TIMESTAMP)', supplied_token).
+        first
+      if api_client_auth.andand.user
+        user = api_client_auth.user
+        api_client = api_client_auth.api_client
+      else
+        # Token seems valid, but points to a non-existent (deleted?) user.
+        api_client_auth = nil
+      end
+    end
+    Thread.current[:api_client_ip_address] = remote_ip
+    Thread.current[:api_client_authorization] = api_client_auth
+    Thread.current[:api_client_uuid] = api_client.andand.uuid
+    Thread.current[:api_client] = api_client
+    Thread.current[:user] = user
+    if api_client_auth
+      api_client_auth.last_used_at = Time.now
+      api_client_auth.last_used_by_ip_address = remote_ip.to_s
+      api_client_auth.save validate: false
+    end
+
+    @app.call env
+  end
+end
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index f0f846c..3a79810 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -295,7 +295,7 @@ class ArvadosModel < ActiveRecord::Base
     log = Log.new(event_type: event_type).fill_object(self)
     yield log
     log.save!
-    connection.execute "NOTIFY logs"
+    connection.execute "NOTIFY logs, '#{log.id}'"
     log_start_state
   end
 
diff --git a/services/api/config/initializers/authorization.rb b/services/api/config/initializers/authorization.rb
new file mode 100644
index 0000000..e491e40
--- /dev/null
+++ b/services/api/config/initializers/authorization.rb
@@ -0,0 +1,5 @@
+Server::Application.configure do
+  config.middleware.insert_before ActionDispatch::Static, ArvadosApiToken
+  config.middleware.delete ActionDispatch::RemoteIp
+  config.middleware.insert_before ArvadosApiToken, ActionDispatch::RemoteIp
+end
diff --git a/services/api/config/initializers/eventbus.rb b/services/api/config/initializers/eventbus.rb
index a065632..31d8fac 100644
--- a/services/api/config/initializers/eventbus.rb
+++ b/services/api/config/initializers/eventbus.rb
@@ -1,5 +1,5 @@
 require 'eventbus'
 
 Server::Application.configure do
-  config.middleware.insert_before ActionDispatch::Static, RackSocket, {:handler => EventBus}
+  config.middleware.insert_after ArvadosApiToken, RackSocket, {:handler => EventBus}
 end
diff --git a/services/api/lib/eventbus.rb b/services/api/lib/eventbus.rb
index ff3cd8b..30b400c 100644
--- a/services/api/lib/eventbus.rb
+++ b/services/api/lib/eventbus.rb
@@ -3,28 +3,37 @@ require 'oj'
 require 'faye/websocket'
 
 class EventBus
+  include CurrentApiClient
+
   def initialize
     @channel = EventMachine::Channel.new
-    @bgthread = nil
+    @mtx = Mutex.new
+    @bgthread = false
   end
 
   def on_connect ws
-      sub = @channel.subscribe do |msg|
-        puts "sending #{msg}"
-        ws.send({:message => "log"}.to_json)
-      end
+    if not current_user
+      ws.send '{"error":"Not logged in"}'
+      ws.close
+      return
+    end
 
-      ws.on :message do |event|
-        puts "got #{event.data}"
-        ws.send(event.data)
+    sub = @channel.subscribe do |msg|
+      Log.where(id: msg.to_i).each do |l|
+        ws.send(l.as_api_response.to_json)
       end
+    end
 
-      ws.on :close do |event|
-        p [:close, event.code, event.reason]
-        @channel.unsubscribe sub
-        ws = nil
-      end
+    ws.on :message do |event|
+      #puts "got #{event.data}"
+    end
 
+    ws.on :close do |event|
+      @channel.unsubscribe sub
+      ws = nil
+    end
+
+    @mtx.synchronize do
       unless @bgthread
         @bgthread = true
         Thread.new do
@@ -35,10 +44,7 @@ class EventBus
               conn.async_exec "LISTEN logs"
               while true
                 conn.wait_for_notify do |channel, pid, payload|
-                  puts "Received a NOTIFY on channel #{channel}"
-                  puts "from PG backend #{pid}"
-                  puts "saying #{payload}"
-                  @channel.push true
+                  @channel.push payload
                 end
               end
             ensure
@@ -50,6 +56,6 @@ class EventBus
           end
         end
       end
-
+    end
   end
 end

commit e484a466d78c87114779b596d6ecd79f22088ee2
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date:   Tue Apr 22 09:47:38 2014 -0400

    Moved application-specific code out from rack_socket to lib/eventbus.rb

diff --git a/services/api/app/middlewares/rack_socket.rb b/services/api/app/middlewares/rack_socket.rb
index 779c675..f13316f 100644
--- a/services/api/app/middlewares/rack_socket.rb
+++ b/services/api/app/middlewares/rack_socket.rb
@@ -1,6 +1,5 @@
 require 'rack'
 require 'faye/websocket'
-require 'oj'
 require 'eventmachine'
 
 class RackSocket
@@ -38,8 +37,7 @@ class RackSocket
       }
     end
 
-    @channel = EventMachine::Channel.new
-    @bgthread = nil
+    @handler = @options[:handler].new
   end
 
   def call env
@@ -47,47 +45,7 @@ class RackSocket
     if request.path_info == @endpoint and Faye::WebSocket.websocket?(env)
       ws = Faye::WebSocket.new(env)
 
-      sub = @channel.subscribe do |msg|
-        puts "sending #{msg}"
-        ws.send({:message => "log"}.to_json)
-      end
-
-      ws.on :message do |event|
-        puts "got #{event.data}"
-        ws.send(event.data)
-      end
-
-      ws.on :close do |event|
-        p [:close, event.code, event.reason]
-        @channel.unsubscribe sub
-        ws = nil
-      end
-
-      unless @bgthread
-        @bgthread = true
-        Thread.new do
-          # from http://stackoverflow.com/questions/16405520/postgres-listen-notify-rails
-          ActiveRecord::Base.connection_pool.with_connection do |connection|
-            conn = connection.instance_variable_get(:@connection)
-            begin
-              conn.async_exec "LISTEN logs"
-              while true
-                conn.wait_for_notify do |channel, pid, payload|
-                  puts "Received a NOTIFY on channel #{channel}"
-                  puts "from PG backend #{pid}"
-                  puts "saying #{payload}"
-                  @channel.push true
-                end
-              end
-            ensure
-              # Don't want the connection to still be listening once we return
-              # it to the pool - could result in weird behavior for the next
-              # thread to check it out.
-              conn.async_exec "UNLISTEN *"
-            end
-          end
-        end
-      end
+      @handler.on_connect ws
 
       # Return async Rack response
       ws.rack_response
@@ -97,5 +55,3 @@ class RackSocket
   end
 
 end
-
-
diff --git a/services/api/config/initializers/eventbus.rb b/services/api/config/initializers/eventbus.rb
index 2350b57..a065632 100644
--- a/services/api/config/initializers/eventbus.rb
+++ b/services/api/config/initializers/eventbus.rb
@@ -1,3 +1,5 @@
+require 'eventbus'
+
 Server::Application.configure do
-  config.middleware.insert_before ActionDispatch::Static, RackSocket
+  config.middleware.insert_before ActionDispatch::Static, RackSocket, {:handler => EventBus}
 end
diff --git a/services/api/lib/eventbus.rb b/services/api/lib/eventbus.rb
new file mode 100644
index 0000000..ff3cd8b
--- /dev/null
+++ b/services/api/lib/eventbus.rb
@@ -0,0 +1,55 @@
+require 'eventmachine'
+require 'oj'
+require 'faye/websocket'
+
+class EventBus
+  def initialize
+    @channel = EventMachine::Channel.new
+    @bgthread = nil
+  end
+
+  def on_connect ws
+      sub = @channel.subscribe do |msg|
+        puts "sending #{msg}"
+        ws.send({:message => "log"}.to_json)
+      end
+
+      ws.on :message do |event|
+        puts "got #{event.data}"
+        ws.send(event.data)
+      end
+
+      ws.on :close do |event|
+        p [:close, event.code, event.reason]
+        @channel.unsubscribe sub
+        ws = nil
+      end
+
+      unless @bgthread
+        @bgthread = true
+        Thread.new do
+          # from http://stackoverflow.com/questions/16405520/postgres-listen-notify-rails
+          ActiveRecord::Base.connection_pool.with_connection do |connection|
+            conn = connection.instance_variable_get(:@connection)
+            begin
+              conn.async_exec "LISTEN logs"
+              while true
+                conn.wait_for_notify do |channel, pid, payload|
+                  puts "Received a NOTIFY on channel #{channel}"
+                  puts "from PG backend #{pid}"
+                  puts "saying #{payload}"
+                  @channel.push true
+                end
+              end
+            ensure
+              # Don't want the connection to still be listening once we return
+              # it to the pool - could result in weird behavior for the next
+              # thread to check it out.
+              conn.async_exec "UNLISTEN *"
+            end
+          end
+        end
+      end
+
+  end
+end

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list