OSDN Git Service

Refactor grack auth module. Add git over http wiki support
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Fri, 14 Jun 2013 11:42:55 +0000 (14:42 +0300)
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Fri, 14 Jun 2013 11:42:55 +0000 (14:42 +0300)
lib/gitlab/backend/grack_auth.rb
lib/gitlab/backend/grack_helpers.rb [new file with mode: 0644]
lib/gitlab/backend/grack_ldap.rb [new file with mode: 0644]

index 4f3f7b0..e7217c7 100644 (file)
@@ -1,9 +1,13 @@
 require_relative 'shell_env'
-require 'omniauth-ldap'
+require_relative 'grack_ldap'
+require_relative 'grack_helpers'
 
 module Grack
   class Auth < Rack::Auth::Basic
-    attr_accessor :user, :project
+    include LDAP
+    include Helpers
+
+    attr_accessor :user, :project, :ref, :env
 
     def call(env)
       @env = env
@@ -14,42 +18,52 @@ module Grack
       @env['PATH_INFO'] = @request.path
       @env['SCRIPT_NAME'] = ""
 
-      return render_not_found unless project
-      return unauthorized unless project.public || @auth.provided?
-      return bad_request if @auth.provided? && !@auth.basic?
-
-      if valid?
-        if @auth.provided?
-          @env['REMOTE_USER'] = @auth.username
-        end
-        return @app.call(env)
-      else
-        unauthorized
-      end
+      auth!
     end
 
-    def valid?
+    private
+
+    def auth!
+      return render_not_found unless project
+
       if @auth.provided?
+        return bad_request unless @auth.basic?
+
         # Authentication with username and password
         login, password = @auth.credentials
 
-        @user = authenticate(login, password)
-        return false unless @user
+        @user = authenticate_user(login, password)
 
-        Gitlab::ShellEnv.set_env(@user)
+        if @user
+          Gitlab::ShellEnv.set_env(@user)
+          @env['REMOTE_USER'] = @auth.username
+        else
+          return unauthorized
+        end
+
+      else
+        return unauthorized unless project.public
       end
 
+      if authorized_git_request?
+        @app.call(env)
+      else
+        unauthorized
+      end
+    end
+
+    def authorized_git_request?
       # Git upload and receive
       if @request.get?
-        validate_get_request
+        authorize_request(@request.params['service'])
       elsif @request.post?
-        validate_post_request
+        authorize_request(File.basename(@request.path))
       else
         false
       end
     end
 
-    def authenticate(login, password)
+    def authenticate_user(login, password)
       user = User.find_by_email(login) || User.find_by_username(login)
 
       # If the provided login was not a known email or username
@@ -65,34 +79,12 @@ module Grack
       end
     end
 
-    def ldap_auth(login, password)
-      # Check user against LDAP backend if user is not authenticated
-      # Only check with valid login and password to prevent anonymous bind results
-      return nil unless ldap_conf.enabled && !login.blank? && !password.blank?
-
-      ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
-      ldap_user = ldap.bind_as(
-        filter: Net::LDAP::Filter.eq(ldap.uid, login),
-        size: 1,
-        password: password
-      )
-
-      User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user
-    end
-
-    def validate_get_request
-      validate_request(@request.params['service'])
-    end
-
-    def validate_post_request
-      validate_request(File.basename(@request.path))
-    end
-
-    def validate_request(service)
-      if service == 'git-upload-pack'
+    def authorize_request(service)
+      case service
+      when 'git-upload-pack'
         project.public || can?(user, :download_code, project)
-      elsif service == 'git-receive-pack'
-        action = if project.protected_branch?(current_ref)
+      when'git-receive-pack'
+        action = if project.protected_branch?(ref)
                    :push_code_to_protected_branches
                  else
                    :push_code
@@ -104,49 +96,24 @@ module Grack
       end
     end
 
-    def can?(object, action, subject)
-      abilities.allowed?(object, action, subject)
-    end
-
-    def current_ref
-      if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
-        input = Zlib::GzipReader.new(@request.body).read
-      else
-        input = @request.body.read
-      end
-      # Need to reset seek point
-      @request.body.rewind
-      /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last
-    end
-
     def project
-      unless instance_variable_defined? :@project
-        # Find project by PATH_INFO from env
-        if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a
-          @project = Project.find_with_namespace(m.last)
-        end
-      end
-      return @project
+      @project ||= project_by_path(@request.path_info)
     end
 
-    PLAIN_TYPE = {"Content-Type" => "text/plain"}
-
-    def render_not_found
-      [404, PLAIN_TYPE, ["Not Found"]]
+    def ref
+      @ref ||= parse_ref
     end
 
-    protected
+    def parse_ref
+      input = if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
+                Zlib::GzipReader.new(@request.body).read
+              else
+                @request.body.read
+              end
 
-    def abilities
-      @abilities ||= begin
-                       abilities = Six.new
-                       abilities << Ability
-                       abilities
-                     end
-    end
-
-    def ldap_conf
-      @ldap_conf ||= Gitlab.config.ldap
+      # Need to reset seek point
+      @request.body.rewind
+      /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last
     end
-  end# Auth
-end# Grack
+  end
+end
diff --git a/lib/gitlab/backend/grack_helpers.rb b/lib/gitlab/backend/grack_helpers.rb
new file mode 100644 (file)
index 0000000..88b2d16
--- /dev/null
@@ -0,0 +1,28 @@
+module Grack
+  module Helpers
+    def project_by_path(path)
+      if m = /^\/([\w\.\/-]+)\.git/.match(path).to_a
+        path_with_namespace = m.last
+        path_with_namespace.gsub!(/.wiki$/, '')
+
+        Project.find_with_namespace(path_with_namespace)
+      end
+    end
+
+    def render_not_found
+      [404, {"Content-Type" => "text/plain"}, ["Not Found"]]
+    end
+
+    def can?(object, action, subject)
+      abilities.allowed?(object, action, subject)
+    end
+
+    def abilities
+      @abilities ||= begin
+                       abilities = Six.new
+                       abilities << Ability
+                       abilities
+                     end
+    end
+  end
+end
diff --git a/lib/gitlab/backend/grack_ldap.rb b/lib/gitlab/backend/grack_ldap.rb
new file mode 100644 (file)
index 0000000..45e98fb
--- /dev/null
@@ -0,0 +1,24 @@
+require 'omniauth-ldap'
+
+module Grack
+  module LDAP
+    def ldap_auth(login, password)
+      # Check user against LDAP backend if user is not authenticated
+      # Only check with valid login and password to prevent anonymous bind results
+      return nil unless ldap_conf.enabled && !login.blank? && !password.blank?
+
+      ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
+      ldap_user = ldap.bind_as(
+        filter: Net::LDAP::Filter.eq(ldap.uid, login),
+        size: 1,
+        password: password
+      )
+
+      User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user
+    end
+
+    def ldap_conf
+      @ldap_conf ||= Gitlab.config.ldap
+    end
+  end
+end