Commit b4e8fea274ff18717391e1c220342d82b965a22f

Authored by Dmitriy Zaporozhets
1 parent a8bcb9a5

Refactor grack auth module. Add git over http wiki support

lib/gitlab/backend/grack_auth.rb
1 1 require_relative 'shell_env'
2   -require 'omniauth-ldap'
  2 +require_relative 'grack_ldap'
  3 +require_relative 'grack_helpers'
3 4  
4 5 module Grack
5 6 class Auth < Rack::Auth::Basic
6   - attr_accessor :user, :project
  7 + include LDAP
  8 + include Helpers
  9 +
  10 + attr_accessor :user, :project, :ref, :env
7 11  
8 12 def call(env)
9 13 @env = env
... ... @@ -14,42 +18,52 @@ module Grack
14 18 @env['PATH_INFO'] = @request.path
15 19 @env['SCRIPT_NAME'] = ""
16 20  
17   - return render_not_found unless project
18   - return unauthorized unless project.public || @auth.provided?
19   - return bad_request if @auth.provided? && !@auth.basic?
20   -
21   - if valid?
22   - if @auth.provided?
23   - @env['REMOTE_USER'] = @auth.username
24   - end
25   - return @app.call(env)
26   - else
27   - unauthorized
28   - end
  21 + auth!
29 22 end
30 23  
31   - def valid?
  24 + private
  25 +
  26 + def auth!
  27 + return render_not_found unless project
  28 +
32 29 if @auth.provided?
  30 + return bad_request unless @auth.basic?
  31 +
33 32 # Authentication with username and password
34 33 login, password = @auth.credentials
35 34  
36   - @user = authenticate(login, password)
37   - return false unless @user
  35 + @user = authenticate_user(login, password)
38 36  
39   - Gitlab::ShellEnv.set_env(@user)
  37 + if @user
  38 + Gitlab::ShellEnv.set_env(@user)
  39 + @env['REMOTE_USER'] = @auth.username
  40 + else
  41 + return unauthorized
  42 + end
  43 +
  44 + else
  45 + return unauthorized unless project.public
40 46 end
41 47  
  48 + if authorized_git_request?
  49 + @app.call(env)
  50 + else
  51 + unauthorized
  52 + end
  53 + end
  54 +
  55 + def authorized_git_request?
42 56 # Git upload and receive
43 57 if @request.get?
44   - validate_get_request
  58 + authorize_request(@request.params['service'])
45 59 elsif @request.post?
46   - validate_post_request
  60 + authorize_request(File.basename(@request.path))
47 61 else
48 62 false
49 63 end
50 64 end
51 65  
52   - def authenticate(login, password)
  66 + def authenticate_user(login, password)
53 67 user = User.find_by_email(login) || User.find_by_username(login)
54 68  
55 69 # If the provided login was not a known email or username
... ... @@ -65,34 +79,12 @@ module Grack
65 79 end
66 80 end
67 81  
68   - def ldap_auth(login, password)
69   - # Check user against LDAP backend if user is not authenticated
70   - # Only check with valid login and password to prevent anonymous bind results
71   - return nil unless ldap_conf.enabled && !login.blank? && !password.blank?
72   -
73   - ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
74   - ldap_user = ldap.bind_as(
75   - filter: Net::LDAP::Filter.eq(ldap.uid, login),
76   - size: 1,
77   - password: password
78   - )
79   -
80   - User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user
81   - end
82   -
83   - def validate_get_request
84   - validate_request(@request.params['service'])
85   - end
86   -
87   - def validate_post_request
88   - validate_request(File.basename(@request.path))
89   - end
90   -
91   - def validate_request(service)
92   - if service == 'git-upload-pack'
  82 + def authorize_request(service)
  83 + case service
  84 + when 'git-upload-pack'
93 85 project.public || can?(user, :download_code, project)
94   - elsif service == 'git-receive-pack'
95   - action = if project.protected_branch?(current_ref)
  86 + when'git-receive-pack'
  87 + action = if project.protected_branch?(ref)
96 88 :push_code_to_protected_branches
97 89 else
98 90 :push_code
... ... @@ -104,49 +96,24 @@ module Grack
104 96 end
105 97 end
106 98  
107   - def can?(object, action, subject)
108   - abilities.allowed?(object, action, subject)
109   - end
110   -
111   - def current_ref
112   - if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
113   - input = Zlib::GzipReader.new(@request.body).read
114   - else
115   - input = @request.body.read
116   - end
117   - # Need to reset seek point
118   - @request.body.rewind
119   - /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last
120   - end
121   -
122 99 def project
123   - unless instance_variable_defined? :@project
124   - # Find project by PATH_INFO from env
125   - if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a
126   - @project = Project.find_with_namespace(m.last)
127   - end
128   - end
129   - return @project
  100 + @project ||= project_by_path(@request.path_info)
130 101 end
131 102  
132   - PLAIN_TYPE = {"Content-Type" => "text/plain"}
133   -
134   - def render_not_found
135   - [404, PLAIN_TYPE, ["Not Found"]]
  103 + def ref
  104 + @ref ||= parse_ref
136 105 end
137 106  
138   - protected
  107 + def parse_ref
  108 + input = if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/
  109 + Zlib::GzipReader.new(@request.body).read
  110 + else
  111 + @request.body.read
  112 + end
139 113  
140   - def abilities
141   - @abilities ||= begin
142   - abilities = Six.new
143   - abilities << Ability
144   - abilities
145   - end
146   - end
147   -
148   - def ldap_conf
149   - @ldap_conf ||= Gitlab.config.ldap
  114 + # Need to reset seek point
  115 + @request.body.rewind
  116 + /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last
150 117 end
151   - end# Auth
152   -end# Grack
  118 + end
  119 +end
... ...
lib/gitlab/backend/grack_helpers.rb 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +module Grack
  2 + module Helpers
  3 + def project_by_path(path)
  4 + if m = /^\/([\w\.\/-]+)\.git/.match(path).to_a
  5 + path_with_namespace = m.last
  6 + path_with_namespace.gsub!(/.wiki$/, '')
  7 +
  8 + Project.find_with_namespace(path_with_namespace)
  9 + end
  10 + end
  11 +
  12 + def render_not_found
  13 + [404, {"Content-Type" => "text/plain"}, ["Not Found"]]
  14 + end
  15 +
  16 + def can?(object, action, subject)
  17 + abilities.allowed?(object, action, subject)
  18 + end
  19 +
  20 + def abilities
  21 + @abilities ||= begin
  22 + abilities = Six.new
  23 + abilities << Ability
  24 + abilities
  25 + end
  26 + end
  27 + end
  28 +end
... ...
lib/gitlab/backend/grack_ldap.rb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +require 'omniauth-ldap'
  2 +
  3 +module Grack
  4 + module LDAP
  5 + def ldap_auth(login, password)
  6 + # Check user against LDAP backend if user is not authenticated
  7 + # Only check with valid login and password to prevent anonymous bind results
  8 + return nil unless ldap_conf.enabled && !login.blank? && !password.blank?
  9 +
  10 + ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf)
  11 + ldap_user = ldap.bind_as(
  12 + filter: Net::LDAP::Filter.eq(ldap.uid, login),
  13 + size: 1,
  14 + password: password
  15 + )
  16 +
  17 + User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user
  18 + end
  19 +
  20 + def ldap_conf
  21 + @ldap_conf ||= Gitlab.config.ldap
  22 + end
  23 + end
  24 +end
... ...