Merge remote-tracking branch 'origin/master' into pete-fixes
authorPeter Amstutz <peter.amstutz@curoverse.com>
Tue, 24 Jun 2014 20:04:10 +0000 (16:04 -0400)
committerPeter Amstutz <peter.amstutz@curoverse.com>
Tue, 24 Jun 2014 20:04:10 +0000 (16:04 -0400)
1  2 
apps/workbench/app/controllers/application_controller.rb
services/fuse/bin/arv-mount

index ec2e95afd2ed065530459d25baf00a0f87d2ba6d,d0496cb42a116e05adc99eadcb4adb883260ce17..38ae911b5c3365e182362d9abc68824ef43aee15
@@@ -8,8 -8,10 +8,10 @@@ class ApplicationController < ActionCon
    ERROR_ACTIONS = [:render_error, :render_not_found]
  
    around_filter :thread_clear
-   around_filter :thread_with_mandatory_api_token, except: ERROR_ACTIONS
-   around_filter :thread_with_optional_api_token
+   around_filter :set_thread_api_token
+   # Methods that don't require login should
+   #   skip_around_filter :require_thread_api_token
+   around_filter :require_thread_api_token, except: ERROR_ACTIONS
    before_filter :check_user_agreements, except: ERROR_ACTIONS
    before_filter :check_user_notifications, except: ERROR_ACTIONS
    before_filter :find_object_by_uuid, except: [:index, :choose] + ERROR_ACTIONS
      else
        @errors = [e.to_s]
      end
-     self.render_error status: 422
+     if e.is_a? ArvadosApiClient::NotLoggedInException
+       self.render_error status: 422
+     else
+       set_thread_api_token do
+         self.render_error status: 422
+       end
+     end
    end
  
    def render_not_found(e=ActionController::RoutingError.new("Path not found"))
      logger.error e.inspect
      @errors = ["Path not found"]
-     self.render_error status: 404
+     set_thread_api_token do
+       self.render_error status: 404
+     end
    end
  
    def find_objects_for_index
  
    protected
  
+   def strip_token_from_path(path)
+     path.sub(/([\?&;])api_token=[^&;]*[&;]?/, '\1')
+   end
    def redirect_to_login
      respond_to do |f|
        f.html {
          if request.method.in? ['GET', 'HEAD']
-           redirect_to arvados_api_client.arvados_login_url(return_to: request.url)
+           redirect_to arvados_api_client.arvados_login_url(return_to: strip_token_from_path(request.url))
          else
            flash[:error] = "Either you are not logged in, or your session has timed out. I can't automatically log you in and re-attempt this request."
            redirect_to :back
      Rails.cache.delete_matched(/^request_#{Thread.current.object_id}_/)
    end
  
-   def thread_with_api_token(login_optional = false)
+   # Save the session API token in thread-local storage, and yield.
+   # This method also takes care of session setup if the request
+   # provides a valid api_token parameter.
+   # If a token is unavailable or expired, the block is still run, with
+   # a nil token.
+   def set_thread_api_token
+     # If an API token has already been found, pass it through.
+     if Thread.current[:arvados_api_token]
+       yield
+       return
+     end
      begin
-       try_redirect_to_login = true
-       if params[:api_token]
-         try_redirect_to_login = false
-         Thread.current[:arvados_api_token] = params[:api_token]
-         # Before copying the token into session[], do a simple API
-         # call to verify its authenticity.
-         if verify_api_token
-           session[:arvados_api_token] = params[:api_token]
-           u = User.current
-           session[:user] = {
-             uuid: u.uuid,
-             email: u.email,
-             first_name: u.first_name,
-             last_name: u.last_name,
-             is_active: u.is_active,
-             is_admin: u.is_admin,
-             prefs: u.prefs
-           }
-           if !request.format.json? and request.method.in? ['GET', 'HEAD']
-             # Repeat this request with api_token in the (new) session
-             # cookie instead of the query string.  This prevents API
-             # tokens from appearing in (and being inadvisedly copied
-             # and pasted from) browser Location bars.
-             redirect_to request.fullpath.sub(%r{([&\?]api_token=)[^&\?]*}, '')
-           else
-             yield
-           end
-         else
-           @errors = ['Invalid API token']
-           self.render_error status: 401
-         end
-       elsif session[:arvados_api_token]
-         # In this case, the token must have already verified at some
-         # point, but it might have been revoked since.  We'll try
-         # using it, and catch the exception if it doesn't work.
-         try_redirect_to_login = false
-         Thread.current[:arvados_api_token] = session[:arvados_api_token]
-         begin
-           yield
-         rescue ArvadosApiClient::NotLoggedInException
-           try_redirect_to_login = true
+       # If there's a valid api_token parameter, use it to set up the session.
+       if (Thread.current[:arvados_api_token] = params[:api_token]) and
+           verify_api_token
+         session[:arvados_api_token] = params[:api_token]
+         u = User.current
+         session[:user] = {
+           uuid: u.uuid,
+           email: u.email,
+           first_name: u.first_name,
+           last_name: u.last_name,
+           is_active: u.is_active,
+           is_admin: u.is_admin,
+           prefs: u.prefs
+         }
+         if !request.format.json? and request.method.in? ['GET', 'HEAD']
+           # Repeat this request with api_token in the (new) session
+           # cookie instead of the query string.  This prevents API
+           # tokens from appearing in (and being inadvisedly copied
+           # and pasted from) browser Location bars.
+           redirect_to strip_token_from_path(request.fullpath)
+           return
          end
-       else
-         logger.debug "No token received, session is #{session.inspect}"
        end
-       if try_redirect_to_login
-         unless login_optional
-           redirect_to_login
-         else
-           # login is optional for this route so go on to the regular controller
+       # With setup done, handle the request using the session token.
+       Thread.current[:arvados_api_token] = session[:arvados_api_token]
+       begin
+         yield
+       rescue ArvadosApiClient::NotLoggedInException
+         # If we got this error with a token, it must've expired.
+         # Retry the request without a token.
+         unless Thread.current[:arvados_api_token].nil?
            Thread.current[:arvados_api_token] = nil
            yield
          end
      end
    end
  
-   def thread_with_mandatory_api_token
-     thread_with_api_token(true) do
-       if Thread.current[:arvados_api_token]
-         yield
-       elsif session[:arvados_api_token]
-         # Expired session. Clear it before refreshing login so that,
-         # if this login procedure fails, we end up showing the "please
-         # log in" page instead of getting stuck in a redirect loop.
-         session.delete :arvados_api_token
-         redirect_to_login
-       else
-         render 'users/welcome'
-       end
-     end
-   end
-   # This runs after thread_with_mandatory_api_token in the filter chain.
-   def thread_with_optional_api_token
+   # Reroute this request if an API token is unavailable.
+   def require_thread_api_token
      if Thread.current[:arvados_api_token]
-       # We are already inside thread_with_mandatory_api_token.
        yield
+     elsif session[:arvados_api_token]
+       # Expired session. Clear it before refreshing login so that,
+       # if this login procedure fails, we end up showing the "please
+       # log in" page instead of getting stuck in a redirect loop.
+       session.delete :arvados_api_token
+       redirect_to_login
      else
-       # We skipped thread_with_mandatory_api_token. Use the optional version.
-       thread_with_api_token(true) do
-         yield
-       end
+       render 'users/welcome'
      end
    end
  
    def get_n_objects_of_class dataclass, size
      @objects_map_for ||= {}
  
 -    raise ArgumentError, 'Argument is not a data class' unless dataclass.is_a? Class
 +    raise ArgumentError, 'Argument is not a data class' unless dataclass.is_a? ArvadosBase
      raise ArgumentError, 'Argument is not a valid limit size' unless (size && size>0)
  
      # if the objects_map_for has a value for this dataclass, and the
index 2988c25c7d96895f20fe843c39ce45394c90bdd0,db8e852b4cea27f96c6424f3509b3549dd8b14b8..726741e3b01619b79b62094662d76e819e9b38df
@@@ -1,11 -1,13 +1,13 @@@
  #!/usr/bin/env python
  
- from arvados_fuse import *
- import arvados
- import subprocess
  import argparse
+ import arvados
  import daemon
+ import os
  import signal
+ import subprocess
+ from arvados_fuse import *
  
  if __name__ == '__main__':
      # Handle command line parameters
@@@ -36,10 -38,7 +38,10 @@@ collections on the server."""
      args = parser.parse_args()
  
      # Create the request handler
 -    operations = Operations(os.getuid(), os.getgid())
 +    operations = Operations(os.getuid(), os.getgid(), args.debug)
 +
 +    if args.debug:
 +        arvados.config.settings()['ARVADOS_DEBUG'] = 'true'
  
      if args.groups:
          api = arvados.api('v1')
  
          exit(rc)
      else:
-         if args.foreground:
-             # Initialize the fuse connection
-             llfuse.init(operations, args.mountpoint, opts)
-             llfuse.main()
-         else:
-             # Initialize the fuse connection
-             llfuse.init(operations, args.mountpoint, opts)
-             with daemon.DaemonContext():
-                 llfuse.main()
+         os.chdir(args.mountpoint)
+         if not args.foreground:
+             daemon_ctx = daemon.DaemonContext(working_directory='.')
+             daemon_ctx.open()
+         llfuse.init(operations, '.', opts)
+         llfuse.main()