require 'rack/auth/basic' require 'hws_settings' require 'cloud/auth' module Auth # We setup our middleware to generally require Basic authentication that # indicates our Perforce login and ticket. # # This should be applied *after* HWSSettings, since we might not know which # server we are connecting to. class Middleware def initialize(app, options = {}) @app = app @unauthenticated_paths = [] if options[:unauthenticated_paths] @unauthenticated_paths.concat(options[:unauthenticated_paths]) end end def call(env) return @app.call(env) if unauthenticated_path?(env) auth = Rack::Auth::Basic::Request.new(env) if auth.provided? && auth.basic? Cloud::Settings.cloud_enabled? ? begin return unauthenticated_error unless Cloud::Auth::valid_session?(env, auth) rescue Exception => e env['AUTH_CREDENTIALS'] = nil env['p4'] = nil return unauthenticated_error end : begin check_and_establish_p4_session(env, auth) rescue P4Exception env['AUTH_CREDENTIALS'] = nil env['p4'] = nil return unauthenticated_error end return @app.call(env) end unauthenticated_error end def check_and_establish_p4_session(env, auth) env['AUTH_CREDENTIALS'] = auth.credentials p4 = P4Util.open_from_env(env) p4.connect results = p4.run_user('-o') env['p4.user'] = results.first env['p4'] = p4 end def unauthenticated_path?(env) @unauthenticated_paths.any? do |pathspec| (env['REQUEST_METHOD'] == pathspec[:method]) && ((pathspec[:path].is_a?(String) && pathspec[:path] == env['PATH_INFO']) || (pathspec[:path].is_a?(Regexp) && pathspec[:path].match(env['PATH_INFO']))) end end def unauthenticated_error [ 403, { 'Content-Type' => 'text/plain', 'Content-Length' => '0', 'WWW-Authenticate' => 'Basic realm="Perforce Web API"' }, [] ] end end end