whimsy-asf 0.0.24 → 0.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/asf.version +1 -1
- data/lib/whimsy/asf/ldap.rb +73 -23
- data/lib/whimsy/asf/rack.rb +9 -11
- metadata +1 -1
data/asf.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.25
|
data/lib/whimsy/asf/ldap.rb
CHANGED
@@ -2,38 +2,22 @@ require 'wunderbar'
|
|
2
2
|
require 'ldap'
|
3
3
|
|
4
4
|
module ASF
|
5
|
-
|
6
5
|
# determine whether or not the LDAP API can be used
|
7
6
|
def self.init_ldap
|
8
7
|
@ldap = nil
|
9
8
|
|
10
|
-
|
9
|
+
host = ASF::LDAP.host
|
11
10
|
|
12
|
-
|
13
|
-
conf = '/etc/ldap/ldap.conf'
|
14
|
-
if File.exist? conf
|
15
|
-
config = File.read(conf)[/^uri\s+(ldaps?:\/\/\S+?:\d+)/i, 1]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
unless config
|
20
|
-
# https://www.pingmybox.com/dashboard?location=304
|
21
|
-
config = %w(ldaps://ldap1-us-west.apache.org:636
|
22
|
-
ldaps://ldap1-eu-central.apache.org:636
|
23
|
-
ldaps://ldap2-us-west.apache.org:636
|
24
|
-
ldaps://ldap1-us-east.apache.org:636).sample
|
25
|
-
end
|
26
|
-
|
27
|
-
Wunderbar.info "Connecting to LDAP server: #{config}"
|
11
|
+
Wunderbar.info "Connecting to LDAP server: #{host}"
|
28
12
|
|
29
13
|
begin
|
30
|
-
uri = URI.parse(
|
14
|
+
uri = URI.parse(host)
|
31
15
|
if uri.scheme == 'ldaps'
|
32
|
-
@ldap = LDAP::SSLConn.new(uri.host, uri.port)
|
16
|
+
@ldap = ::LDAP::SSLConn.new(uri.host, uri.port)
|
33
17
|
else
|
34
|
-
@ldap = LDAP::Conn.new(uri.host, uri.port)
|
18
|
+
@ldap = ::LDAP::Conn.new(uri.host, uri.port)
|
35
19
|
end
|
36
|
-
rescue LDAP::ResultError=>re
|
20
|
+
rescue ::LDAP::ResultError=>re
|
37
21
|
Wunderbar.error "Error binding to LDAP server: message: ["+ re.message + "]"
|
38
22
|
end
|
39
23
|
end
|
@@ -47,7 +31,7 @@ module ASF
|
|
47
31
|
"#{[attrs].flatten.join(' ')}"
|
48
32
|
|
49
33
|
begin
|
50
|
-
result = @ldap.search2(base, LDAP::LDAP_SCOPE_ONELEVEL, filter, attrs)
|
34
|
+
result = @ldap.search2(base, ::LDAP::LDAP_SCOPE_ONELEVEL, filter, attrs)
|
51
35
|
rescue
|
52
36
|
result = []
|
53
37
|
end
|
@@ -176,6 +160,10 @@ module ASF
|
|
176
160
|
ASF::Member.status[name] or ASF.members.include? self
|
177
161
|
end
|
178
162
|
|
163
|
+
def asf_committer?
|
164
|
+
ASF::Group.new('committers').include? self
|
165
|
+
end
|
166
|
+
|
179
167
|
def banned?
|
180
168
|
not attrs['loginShell'] or attrs['loginShell'].include? "/usr/bin/false"
|
181
169
|
end
|
@@ -212,6 +200,15 @@ module ASF
|
|
212
200
|
ASF.search_one(base, filter, 'cn').flatten.map {|cn| find(cn)}
|
213
201
|
end
|
214
202
|
|
203
|
+
def include?(person)
|
204
|
+
filter = "(&(cn=#{name})(memberUid=#{person.name}))"
|
205
|
+
if ASF.search_one(base, filter, 'cn').empty?
|
206
|
+
return false
|
207
|
+
else
|
208
|
+
return true
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
215
212
|
def members
|
216
213
|
ASF.search_one(base, "cn=#{name}", 'memberUid').flatten.
|
217
214
|
map {|uid| Person.find(uid)}
|
@@ -243,4 +240,57 @@ module ASF
|
|
243
240
|
map {|uid| Person.find uid[/uid=(.*?),/,1]}
|
244
241
|
end
|
245
242
|
end
|
243
|
+
|
244
|
+
module LDAP
|
245
|
+
# select LDAP host
|
246
|
+
def self.host
|
247
|
+
# try whimsy config
|
248
|
+
host = ASF::Config.get(:ldap)
|
249
|
+
|
250
|
+
# check system configuration
|
251
|
+
unless host
|
252
|
+
conf = '/etc/ldap/ldap.conf'
|
253
|
+
if File.exist? conf
|
254
|
+
host = File.read(conf)[/^uri\s+(ldaps?:\/\/\S+?:\d+)/i, 1]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# if all else fails, pick one at random
|
259
|
+
unless host
|
260
|
+
# https://www.pingmybox.com/dashboard?location=304
|
261
|
+
host = %w(ldaps://ldap1-us-west.apache.org:636
|
262
|
+
ldaps://ldap1-eu-central.apache.org:636
|
263
|
+
ldaps://ldap2-us-west.apache.org:636
|
264
|
+
ldaps://ldap1-us-east.apache.org:636).sample
|
265
|
+
end
|
266
|
+
|
267
|
+
host
|
268
|
+
end
|
269
|
+
|
270
|
+
# query and extract cert from openssl output
|
271
|
+
def self.cert
|
272
|
+
host = LDAP.host[%r{//(.*?)(/|$)}, 1]
|
273
|
+
query = "openssl s_client -connect #{host} -showcerts"
|
274
|
+
output = `#{query} < /dev/null 2> /dev/null`
|
275
|
+
output[/^-+BEGIN.*?\n-+END[^\n]+\n/m]
|
276
|
+
end
|
277
|
+
|
278
|
+
# update /etc/ldap.conf. Usage:
|
279
|
+
# sudo ruby -r whimsy/asf -e "ASF::LDAP.configure"
|
280
|
+
def self.configure
|
281
|
+
if not File.exist? "/etc/ldap/asf-ldap-client.pem"
|
282
|
+
File.write "/etc/ldap/asf-ldap-client.pem", self.cert
|
283
|
+
end
|
284
|
+
|
285
|
+
ldap_conf = '/etc/ldap/ldap.conf'
|
286
|
+
content = File.read(ldap_conf)
|
287
|
+
unless content.include? 'asf-ldap-client.pem'
|
288
|
+
content.gsub!(/^TLS_CACERT/, '# TLS_CACERT')
|
289
|
+
content += "TLS_CACERT /etc/ldap/asf-ldap-client.pem\n"
|
290
|
+
content += "uri #{LDAP.host}\n"
|
291
|
+
content += "base dc=apache,dc=org\n"
|
292
|
+
File.write(ldap_conf, content)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
246
296
|
end
|
data/lib/whimsy/asf/rack.rb
CHANGED
@@ -17,7 +17,7 @@ module ASF
|
|
17
17
|
}
|
18
18
|
|
19
19
|
# decode HTTP authorization, when present
|
20
|
-
def self.decode(env
|
20
|
+
def self.decode(env)
|
21
21
|
class << env; attr_accessor :user, :password; end
|
22
22
|
|
23
23
|
if env['HTTP_AUTHORIZATION']
|
@@ -25,25 +25,25 @@ module ASF
|
|
25
25
|
env.user, env.password = Base64.decode64(env['HTTP_AUTHORIZATION'][
|
26
26
|
/^Basic ([A-Za-z0-9+\/=]+)$/,1]).split(':',2)
|
27
27
|
else
|
28
|
-
env.user =
|
28
|
+
env.user = env['REMOTE_USER'] ||= ENV['USER'] || Etc.getpwuid.name
|
29
29
|
end
|
30
|
+
|
31
|
+
ASF::Person.new(env.user)
|
30
32
|
end
|
31
33
|
|
32
34
|
# Simply 'use' the following class in config.ru to limit access
|
33
35
|
# to the application to ASF committers
|
34
36
|
class Committers < Rack::Auth::Basic
|
35
37
|
def initialize(app)
|
36
|
-
super(app, "ASF
|
38
|
+
super(app, "ASF Committers", &proc {})
|
37
39
|
end
|
38
40
|
|
39
41
|
def call(env)
|
40
42
|
authorized = ( ENV['RACK_ENV'] == 'test' )
|
41
43
|
|
42
|
-
|
43
|
-
authorized ||= ASF::Person.new(user)
|
44
|
+
authorized ||= ASF::Auth.decode(env).asf_committer?
|
44
45
|
|
45
46
|
if authorized
|
46
|
-
ASF::Auth.decode(env, user)
|
47
47
|
@app.call(env)
|
48
48
|
else
|
49
49
|
unauthorized
|
@@ -61,21 +61,19 @@ module ASF
|
|
61
61
|
def call(env)
|
62
62
|
authorized = ( ENV['RACK_ENV'] == 'test' )
|
63
63
|
|
64
|
-
|
65
|
-
person = ASF::Person.new(user)
|
64
|
+
person = ASF::Auth.decode(env)
|
66
65
|
|
67
|
-
authorized ||= DIRECTORS[user]
|
66
|
+
authorized ||= DIRECTORS[env.user]
|
68
67
|
authorized ||= person.asf_member?
|
69
68
|
authorized ||= ASF.pmc_chairs.include? person
|
70
69
|
|
71
70
|
if not authorized
|
72
71
|
accounting = ASF::Authorization.new('pit').
|
73
72
|
find {|group, list| group=='accounting'}
|
74
|
-
authorized = (accounting and accounting.last.include? user)
|
73
|
+
authorized = (accounting and accounting.last.include? env.user)
|
75
74
|
end
|
76
75
|
|
77
76
|
if authorized
|
78
|
-
ASF::Auth.decode(env, user)
|
79
77
|
@app.call(env)
|
80
78
|
else
|
81
79
|
unauthorized
|