whimsy-asf 0.0.74 → 0.0.75
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.
- checksums.yaml +4 -4
- data/asf.version +1 -1
- data/lib/whimsy/asf.rb +4 -0
- data/lib/whimsy/asf/committee.rb +15 -2
- data/lib/whimsy/asf/config.rb +15 -2
- data/lib/whimsy/asf/ldap.rb +238 -62
- data/lib/whimsy/asf/rack.rb +5 -4
- data/lib/whimsy/asf/svn.rb +2 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fbe033a993bc2428dbed396c0a98fece7b33f82b
|
|
4
|
+
data.tar.gz: 17ca4624c5340b1354ff01f540999338d426f2b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 801153db8122f912ead1cd2df9a56ad65349bb50c95b1719497dd65da332862c2b3ccbf0e26b92f17981dc1ccb5a34474b2bd1eb4266a6267eb5104b97de34cf
|
|
7
|
+
data.tar.gz: 28230fd4887ed1198b94f5d27bba0d2a38eec271ffeaeaa4d010d4aa9b07129a27ab0bb21b621058df05ed551c2ff621218237cff9a003496c3f5fc316d76824
|
data/asf.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.75
|
data/lib/whimsy/asf.rb
CHANGED
data/lib/whimsy/asf/committee.rb
CHANGED
|
@@ -59,34 +59,47 @@ module ASF
|
|
|
59
59
|
@@svn_change = Time.parse(
|
|
60
60
|
`svn info #{file}`[/Last Changed Date: (.*) \(/, 1]).gmtime
|
|
61
61
|
|
|
62
|
+
# Split the file on lines starting "* ", i.e. the start of each group in section 3
|
|
62
63
|
info = File.read(file).split(/^\* /)
|
|
64
|
+
# Extract the text before first entry in section 3 and split on section headers,
|
|
65
|
+
# keeping sections 1 (COMMITTEES) and 2 (REPORTING).
|
|
63
66
|
head, report = info.shift.split(/^\d\./)[1..2]
|
|
67
|
+
# Drop lines which could match group entries
|
|
64
68
|
head.gsub! /^\s+NAME\s+CHAIR\s*$/,'' # otherwise could match an entry with no e-mail
|
|
65
69
|
|
|
66
70
|
# extract the committee chairs (e-mail address is required here)
|
|
71
|
+
# Note: this includes the non-PMC entries
|
|
67
72
|
head.scan(/^[ \t]+(\w.*?)[ \t][ \t]+(.*)[ \t]+<(.*?)@apache\.org>/).
|
|
68
73
|
each do |committee, name, id|
|
|
69
74
|
list[committee].chairs << {name: name, id: id}
|
|
70
75
|
end
|
|
71
76
|
|
|
72
77
|
# Extract the non-PMC committees (e-mail address may be absent)
|
|
73
|
-
|
|
78
|
+
# first drop leading text so we only match non-PMCs
|
|
79
|
+
@nonpmcs = head.sub(/.*?also has /m,'').
|
|
74
80
|
scan(/^[ \t]+(\w.*?)(?:[ \t][ \t]|[ \t]?$)/).flatten.uniq.
|
|
75
81
|
map {|name| list[name]}
|
|
76
82
|
|
|
83
|
+
# for each committee in section 3
|
|
77
84
|
info.each do |roster|
|
|
85
|
+
# extract the committee name and canonicalise
|
|
78
86
|
committee = list[@@namemap.call(roster[/(\w.*?)\s+\(/,1])]
|
|
87
|
+
# get the start date
|
|
79
88
|
committee.established = roster[/\(est\. (.*?)\)/, 1]
|
|
89
|
+
# Extract any emeritus members (now probably redundant)
|
|
80
90
|
roster.gsub! /^.*\(\s*emeritus\s*\).*/i do |line|
|
|
81
91
|
committee.emeritus += line.scan(/<(.*?)@apache\.org>/).flatten
|
|
82
92
|
''
|
|
83
93
|
end
|
|
94
|
+
# extract the availids (is this used?)
|
|
84
95
|
committee.info = roster.scan(/<(.*?)@apache\.org>/).flatten
|
|
96
|
+
# drop (chair) markers and extract 0: name, 1: availid, 2: [date], 3: date
|
|
85
97
|
committee.roster = Hash[roster.gsub(/\(\w+\)/, '').
|
|
86
98
|
scan(/^\s*(.*?)\s*<(.*?)@apache\.org>\s+(\[(.*?)\])?/).
|
|
87
99
|
map {|list| [list[1], {name: list[0], date: list[3]}]}]
|
|
88
100
|
end
|
|
89
101
|
|
|
102
|
+
# process report section
|
|
90
103
|
report.scan(/^([^\n]+)\n---+\n(.*?)\n\n/m).each do |period, committees|
|
|
91
104
|
committees.scan(/^ \s*(.*)/).each do |committee|
|
|
92
105
|
committee, comment = committee.first.split(/\s+#\s+/,2)
|
|
@@ -101,7 +114,7 @@ module ASF
|
|
|
101
114
|
end
|
|
102
115
|
end
|
|
103
116
|
|
|
104
|
-
@committee_info = list.values
|
|
117
|
+
@committee_info = list.values.uniq
|
|
105
118
|
end
|
|
106
119
|
|
|
107
120
|
def self.nonpmcs
|
data/lib/whimsy/asf/config.rb
CHANGED
|
@@ -9,12 +9,25 @@ module ASF
|
|
|
9
9
|
|
|
10
10
|
@config = YAML.load_file("#@home/.whimsy") rescue {}
|
|
11
11
|
|
|
12
|
-
# default :svn
|
|
13
|
-
@config[:svn] ||=
|
|
12
|
+
# default :svn and :git
|
|
13
|
+
@config[:svn] ||= '/srv/svn/*'
|
|
14
|
+
@config[:git] ||= '/srv/git/*'
|
|
15
|
+
|
|
16
|
+
@config[:lib] ||= []
|
|
17
|
+
|
|
18
|
+
# add gems to lib
|
|
19
|
+
(@config[:gem] || {}).to_a.reverse.each do |name, version|
|
|
20
|
+
begin
|
|
21
|
+
gem = Gem::Specification.find_by_name(name, version)
|
|
22
|
+
@config[:lib] += Dir[gem.lib_dirs_glob]
|
|
23
|
+
rescue Gem::LoadError
|
|
24
|
+
end
|
|
25
|
+
end
|
|
14
26
|
|
|
15
27
|
# add libraries to RUBYLIB, load path
|
|
16
28
|
(@config[:lib] || []).reverse.each do |lib|
|
|
17
29
|
next unless File.exist? lib
|
|
30
|
+
lib = File.realpath(lib)
|
|
18
31
|
ENV['RUBYLIB']=([lib] + ENV['RUBYLIB'].to_s.split(':')).uniq.join(':')
|
|
19
32
|
$LOAD_PATH.unshift lib.untaint unless $LOAD_PATH.include? lib
|
|
20
33
|
end
|
data/lib/whimsy/asf/ldap.rb
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Encapsulate access to LDAP, caching results for performance. For best
|
|
3
|
+
# performance in applications that access large number of objects, make use
|
|
4
|
+
# of the preload methods to pre-fetch multiple objects in a single LDAP
|
|
5
|
+
# call, and rely on the cache to find the objects later.
|
|
6
|
+
#
|
|
7
|
+
# The cache makes heavy use of Weak References internally to enable garbage
|
|
8
|
+
# collection to reclaim objects; among other things, this ensures that
|
|
9
|
+
# LDAP results don't become too stale.
|
|
10
|
+
#
|
|
11
|
+
# Until garbage collection reclaims an object, calls to find methods for the
|
|
12
|
+
# same name is guaranteed to return the same object. Holding on to the
|
|
13
|
+
# results of find or preload calls (by assigning it to a variable) is
|
|
14
|
+
# sufficient to prevent reclaiming of objects.
|
|
15
|
+
#
|
|
16
|
+
# To illustrate, the following is likely to return the same id twice, followed
|
|
17
|
+
# by a new id:
|
|
18
|
+
# puts ASF::Person.find('rubys').__id__
|
|
19
|
+
# puts ASF::Person.find('rubys').__id__
|
|
20
|
+
# GC.start
|
|
21
|
+
# puts ASF::Person.find('rubys').__id__
|
|
22
|
+
#
|
|
23
|
+
# By contrast, the following is guaranteed to produce the same id three times:
|
|
24
|
+
# rubys1 = ASF::Person.find('rubys')
|
|
25
|
+
# rubys2 = ASF::Person.find('rubys')
|
|
26
|
+
# GC.start
|
|
27
|
+
# rubys3 = ASF::Person.find('rubys')
|
|
28
|
+
# puts [rubys1.__id__, rubys2.__id__, rubys3.__id__]
|
|
29
|
+
#
|
|
30
|
+
|
|
1
31
|
require 'wunderbar'
|
|
2
32
|
require 'ldap'
|
|
3
33
|
require 'weakref'
|
|
34
|
+
require 'net/http'
|
|
35
|
+
require 'base64'
|
|
4
36
|
|
|
5
37
|
module ASF
|
|
6
38
|
module LDAP
|
|
@@ -8,41 +40,80 @@ module ASF
|
|
|
8
40
|
# https://github.com/apache/infrastructure-puppet/blob/deployment/data/common.yaml (ldapserver::slapd_peers)
|
|
9
41
|
HOSTS = %w(
|
|
10
42
|
ldaps://ldap1-us-west.apache.org:636
|
|
11
|
-
ldaps://ldap1-
|
|
43
|
+
ldaps://ldap1-lw-us.apache.org:636
|
|
12
44
|
ldaps://ldap2-us-west.apache.org:636
|
|
13
|
-
ldaps://ldap1-
|
|
45
|
+
ldaps://ldap1-lw-eu.apache.org:636
|
|
14
46
|
ldaps://snappy5.apache.org:636
|
|
47
|
+
ldaps://ldap2-lw-us.apache.org:636
|
|
48
|
+
ldaps://ldap2-lw-eu.apache.org:636
|
|
15
49
|
)
|
|
16
|
-
end
|
|
17
50
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
51
|
+
# fetch configuration from apache/infrastructure-puppet
|
|
52
|
+
def self.puppet_config
|
|
53
|
+
return @puppet if @puppet
|
|
54
|
+
file = '/apache/infrastructure-puppet/deployment/data/common.yaml'
|
|
55
|
+
http = Net::HTTP.new('raw.githubusercontent.com', 443)
|
|
56
|
+
http.use_ssl = true
|
|
57
|
+
@puppet = YAML.load(http.request(Net::HTTP::Get.new(file)).body)
|
|
58
|
+
end
|
|
24
59
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
60
|
+
# extract the ldapcert from the puppet configuration
|
|
61
|
+
def self.puppet_cert
|
|
62
|
+
puppet_config['ldapclient::ldapcert']
|
|
63
|
+
end
|
|
29
64
|
|
|
30
|
-
|
|
65
|
+
# extract the ldap servers from the puppet configuration
|
|
66
|
+
def self.puppet_ldapservers
|
|
67
|
+
puppet_config['ldapserver::slapd_peers'].values.
|
|
68
|
+
map {|host| "ldaps://#{host}:636"}
|
|
69
|
+
rescue
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
31
72
|
|
|
32
|
-
|
|
73
|
+
# connect to LDAP
|
|
74
|
+
def self.connect
|
|
75
|
+
hosts.shuffle.each do |host|
|
|
76
|
+
Wunderbar.info "Connecting to LDAP server: #{host}"
|
|
77
|
+
|
|
78
|
+
begin
|
|
79
|
+
# request connection
|
|
80
|
+
uri = URI.parse(host)
|
|
81
|
+
if uri.scheme == 'ldaps'
|
|
82
|
+
ldap = ::LDAP::SSLConn.new(uri.host, uri.port)
|
|
83
|
+
else
|
|
84
|
+
ldap = ::LDAP::Conn.new(uri.host, uri.port)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# test the connection
|
|
88
|
+
ldap.bind
|
|
89
|
+
|
|
90
|
+
# save the host
|
|
91
|
+
@host = host
|
|
92
|
+
|
|
93
|
+
return ldap
|
|
94
|
+
rescue ::LDAP::ResultError => re
|
|
95
|
+
Wunderbar.warn "Error connecting to LDAP server #{host}: " +
|
|
96
|
+
re.message + " (continuing)"
|
|
97
|
+
end
|
|
33
98
|
|
|
34
|
-
begin
|
|
35
|
-
uri = URI.parse(host)
|
|
36
|
-
if uri.scheme == 'ldaps'
|
|
37
|
-
@ldap = ::LDAP::SSLConn.new(uri.host, uri.port)
|
|
38
|
-
else
|
|
39
|
-
@ldap = ::LDAP::Conn.new(uri.host, uri.port)
|
|
40
99
|
end
|
|
41
|
-
|
|
42
|
-
|
|
100
|
+
Wunderbar.error "Failed to connect to any LDAP host"
|
|
101
|
+
return nil
|
|
43
102
|
end
|
|
44
103
|
end
|
|
45
104
|
|
|
105
|
+
# backwards compatibility for tools that called this interface
|
|
106
|
+
def self.init_ldap
|
|
107
|
+
@ldap ||= ASF::LDAP.connect
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# determine where ldap.conf resides
|
|
111
|
+
if Dir.exist? '/etc/openldap'
|
|
112
|
+
ETCLDAP = '/etc/openldap'
|
|
113
|
+
else
|
|
114
|
+
ETCLDAP = '/etc/ldap'
|
|
115
|
+
end
|
|
116
|
+
|
|
46
117
|
def self.ldap
|
|
47
118
|
@ldap || self.init_ldap
|
|
48
119
|
end
|
|
@@ -66,30 +137,34 @@ module ASF
|
|
|
66
137
|
result
|
|
67
138
|
end
|
|
68
139
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
140
|
+
# safely dereference a weakref array attribute. Block provided is
|
|
141
|
+
# used when reference is not set or has been reclaimed.
|
|
142
|
+
def self.dereference_weakref(object, attr, &block)
|
|
143
|
+
attr = "@#{attr}"
|
|
144
|
+
value = object.instance_variable_get(attr) || block.call
|
|
145
|
+
value[0..-1]
|
|
146
|
+
rescue WeakRef::RefError
|
|
147
|
+
value = block.call
|
|
148
|
+
ensure
|
|
149
|
+
if value and not value.instance_of? WeakRef
|
|
150
|
+
object.instance_variable_set(attr, WeakRef.new(value))
|
|
72
151
|
end
|
|
152
|
+
end
|
|
73
153
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
instance_variable_set(symbol, nil)
|
|
77
|
-
end
|
|
154
|
+
def self.weakref(attr, &block)
|
|
155
|
+
self.dereference_weakref(self, attr, &block)
|
|
78
156
|
end
|
|
79
157
|
|
|
80
158
|
def self.pmc_chairs
|
|
81
|
-
|
|
82
|
-
@pmc_chairs ||= Service.find('pmc-chairs').members
|
|
159
|
+
weakref(:pmc_chairs) {Service.find('pmc-chairs').members}
|
|
83
160
|
end
|
|
84
161
|
|
|
85
162
|
def self.committers
|
|
86
|
-
|
|
87
|
-
@committers ||= Group.find('committers').members
|
|
163
|
+
weakref(:committers) {Group.find('committers').members}
|
|
88
164
|
end
|
|
89
165
|
|
|
90
166
|
def self.members
|
|
91
|
-
|
|
92
|
-
@members ||= Group.find('member').members
|
|
167
|
+
weakref(:members) {Group.find('member').members}
|
|
93
168
|
end
|
|
94
169
|
|
|
95
170
|
class Base
|
|
@@ -134,6 +209,10 @@ module ASF
|
|
|
134
209
|
self
|
|
135
210
|
end
|
|
136
211
|
|
|
212
|
+
def weakref(attr, &block)
|
|
213
|
+
ASF.dereference_weakref(self, attr, &block)
|
|
214
|
+
end
|
|
215
|
+
|
|
137
216
|
unless Object.respond_to? :id
|
|
138
217
|
def id
|
|
139
218
|
@name
|
|
@@ -213,12 +292,16 @@ module ASF
|
|
|
213
292
|
ASF::Member.status[name] or ASF.members.include? self
|
|
214
293
|
end
|
|
215
294
|
|
|
295
|
+
def asf_officer_or_member?
|
|
296
|
+
asf_member? or ASF.pmc_chairs.include? self
|
|
297
|
+
end
|
|
298
|
+
|
|
216
299
|
def asf_committer?
|
|
217
300
|
ASF::Group.new('committers').include? self
|
|
218
301
|
end
|
|
219
302
|
|
|
220
303
|
def banned?
|
|
221
|
-
not attrs['loginShell'] or attrs['loginShell'].include?
|
|
304
|
+
not attrs['loginShell'] or %w(/usr/bin/false bin/nologin bin/no-cla).any? {|a| attrs['loginShell'].first.include? a}
|
|
222
305
|
end
|
|
223
306
|
|
|
224
307
|
def mail
|
|
@@ -299,9 +382,29 @@ module ASF
|
|
|
299
382
|
end
|
|
300
383
|
end
|
|
301
384
|
|
|
385
|
+
def self.preload
|
|
386
|
+
Hash[ASF.search_one(base, "cn=*", %w(dn memberUid modifyTimestamp)).map do |results|
|
|
387
|
+
cn = results['dn'].first[/^cn=(.*?),/, 1]
|
|
388
|
+
group = ASF::Group.find(cn)
|
|
389
|
+
group.modifyTimestamp = results['modifyTimestamp'].first # it is returned as an array of 1 entry
|
|
390
|
+
members = results['memberUid']
|
|
391
|
+
group.members = members || []
|
|
392
|
+
[group, members]
|
|
393
|
+
end]
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
attr_accessor :modifyTimestamp
|
|
397
|
+
|
|
398
|
+
def members=(members)
|
|
399
|
+
@members = WeakRef.new(members)
|
|
400
|
+
end
|
|
401
|
+
|
|
302
402
|
def members
|
|
303
|
-
|
|
304
|
-
|
|
403
|
+
members = weakref(:members) do
|
|
404
|
+
ASF.search_one(base, "cn=#{name}", 'memberUid').flatten
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
members.map {|uid| Person.find(uid)}
|
|
305
408
|
end
|
|
306
409
|
end
|
|
307
410
|
|
|
@@ -312,9 +415,29 @@ module ASF
|
|
|
312
415
|
ASF.search_one(base, filter, 'cn').flatten.map {|cn| Committee.find(cn)}
|
|
313
416
|
end
|
|
314
417
|
|
|
418
|
+
def self.preload
|
|
419
|
+
Hash[ASF.search_one(base, "cn=*", %w(dn member modifyTimestamp)).map do |results|
|
|
420
|
+
cn = results['dn'].first[/^cn=(.*?),/, 1]
|
|
421
|
+
committee = ASF::Committee.find(cn)
|
|
422
|
+
committee.modifyTimestamp = results['modifyTimestamp'].first # it is returned as an array of 1 entry
|
|
423
|
+
members = results['member']
|
|
424
|
+
committee.members = members
|
|
425
|
+
[committee, members]
|
|
426
|
+
end]
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
attr_accessor :modifyTimestamp
|
|
430
|
+
|
|
431
|
+
def members=(members)
|
|
432
|
+
@members = WeakRef.new(members)
|
|
433
|
+
end
|
|
434
|
+
|
|
315
435
|
def members
|
|
316
|
-
|
|
317
|
-
|
|
436
|
+
members = weakref(:members) do
|
|
437
|
+
ASF.search_one(base, "cn=#{name}", 'member').flatten
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
members.map {|uid| Person.find uid[/uid=(.*?),/,1]}
|
|
318
441
|
end
|
|
319
442
|
|
|
320
443
|
def dn
|
|
@@ -354,59 +477,112 @@ module ASF
|
|
|
354
477
|
module LDAP
|
|
355
478
|
def self.bind(user, password, &block)
|
|
356
479
|
dn = ASF::Person.new(user).dn
|
|
480
|
+
raise ::LDAP::ResultError.new('Unknown user') unless dn
|
|
481
|
+
|
|
482
|
+
ASF.ldap.unbind rescue nil
|
|
357
483
|
if block
|
|
358
484
|
ASF.ldap.bind(dn, password, &block)
|
|
485
|
+
ASF.init_ldap
|
|
359
486
|
else
|
|
360
487
|
ASF.ldap.bind(dn, password)
|
|
361
488
|
end
|
|
362
|
-
ASF.init_ldap
|
|
363
489
|
end
|
|
364
490
|
|
|
365
|
-
#
|
|
366
|
-
|
|
491
|
+
# validate HTTP authorization, and optionally invoke a block bound to
|
|
492
|
+
# that user.
|
|
493
|
+
def self.http_auth(string, &block)
|
|
494
|
+
auth = Base64.decode64(string.to_s[/Basic (.*)/, 1] || '')
|
|
495
|
+
user, password = auth.split(':', 2)
|
|
496
|
+
return unless password
|
|
497
|
+
|
|
498
|
+
if block
|
|
499
|
+
self.bind(user, password, &block)
|
|
500
|
+
else
|
|
501
|
+
begin
|
|
502
|
+
ASF::LDAP.bind(user, password) {}
|
|
503
|
+
return ASF::Person.new(user)
|
|
504
|
+
rescue ::LDAP::ResultError
|
|
505
|
+
return nil
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# determine what LDAP hosts are available
|
|
511
|
+
def self.hosts
|
|
367
512
|
# try whimsy config
|
|
368
|
-
|
|
513
|
+
hosts = Array(ASF::Config.get(:ldap))
|
|
369
514
|
|
|
370
515
|
# check system configuration
|
|
371
|
-
|
|
516
|
+
if hosts.empty?
|
|
372
517
|
conf = "#{ETCLDAP}/ldap.conf"
|
|
373
518
|
if File.exist? conf
|
|
374
|
-
|
|
519
|
+
uris = File.read(conf)[/^uri\s+(.*)/i, 1].to_s
|
|
520
|
+
hosts = uris.scan(/ldaps?:\/\/\S+?:\d+/)
|
|
375
521
|
end
|
|
376
522
|
end
|
|
377
523
|
|
|
378
|
-
# if all else fails,
|
|
379
|
-
|
|
524
|
+
# if all else fails, use default list
|
|
525
|
+
hosts = ASF::LDAP::HOSTS if hosts.empty?
|
|
526
|
+
|
|
527
|
+
hosts
|
|
528
|
+
end
|
|
380
529
|
|
|
381
|
-
|
|
530
|
+
# select LDAP host
|
|
531
|
+
def self.host
|
|
532
|
+
@host ||= hosts.sample
|
|
382
533
|
end
|
|
383
534
|
|
|
384
535
|
# query and extract cert from openssl output
|
|
385
|
-
def self.
|
|
536
|
+
def self.extract_cert
|
|
386
537
|
host = LDAP.host[%r{//(.*?)(/|$)}, 1]
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
538
|
+
puts ['openssl', 's_client', '-connect', host, '-showcerts'].join(' ')
|
|
539
|
+
out, err, rc = Open3.capture3 'openssl', 's_client',
|
|
540
|
+
'-connect', host, '-showcerts'
|
|
541
|
+
out[/^-+BEGIN.*?\n-+END[^\n]+\n/m]
|
|
390
542
|
end
|
|
391
543
|
|
|
392
544
|
# update /etc/ldap.conf. Usage:
|
|
545
|
+
#
|
|
393
546
|
# sudo ruby -r whimsy/asf -e "ASF::LDAP.configure"
|
|
547
|
+
#
|
|
394
548
|
def self.configure
|
|
395
|
-
|
|
396
|
-
|
|
549
|
+
cert = Dir["#{ETCLDAP}/asf*-ldap-client.pem"].first
|
|
550
|
+
|
|
551
|
+
# verify/obtain/write the cert
|
|
552
|
+
if not cert
|
|
553
|
+
cert = "#{ETCLDAP}/asf-ldap-client.pem"
|
|
554
|
+
File.write cert, ASF::LDAP.puppet_cert || self.extract_cert
|
|
397
555
|
end
|
|
398
556
|
|
|
557
|
+
# read the current configuration file
|
|
399
558
|
ldap_conf = "#{ETCLDAP}/ldap.conf"
|
|
400
559
|
content = File.read(ldap_conf)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
560
|
+
|
|
561
|
+
# ensure that the right cert is used
|
|
562
|
+
unless content =~ /asf.*-ldap-client\.pem/
|
|
563
|
+
content.gsub!(/^TLS_CACERT/i, '# TLS_CACERT')
|
|
404
564
|
content += "TLS_CACERT #{ETCLDAP}/asf-ldap-client.pem\n"
|
|
405
|
-
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
# provide the URIs of the ldap hosts
|
|
568
|
+
content.gsub!(/^URI/, '# URI')
|
|
569
|
+
content += "uri \n" unless content =~ /^uri /
|
|
570
|
+
content[/uri (.*)\n/, 1] = hosts.join(' ')
|
|
571
|
+
|
|
572
|
+
# verify/set the base
|
|
573
|
+
unless content.include? 'base dc=apache'
|
|
574
|
+
content.gsub!(/^BASE/i, '# BASE')
|
|
406
575
|
content += "base dc=apache,dc=org\n"
|
|
407
|
-
content += "TLS_REQCERT allow\n" if ETCLDAP.include? 'openldap'
|
|
408
|
-
File.write(ldap_conf, content)
|
|
409
576
|
end
|
|
577
|
+
|
|
578
|
+
# ensure TLS_REQCERT is allow (Mac OS/X only)
|
|
579
|
+
if ETCLDAP.include? 'openldap' and not content.include? 'REQCERT allow'
|
|
580
|
+
content.gsub!(/^TLS_REQCERT/i, '# TLS_REQCERT')
|
|
581
|
+
content += "TLS_REQCERT allow\n"
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# write the configuration if there were any changes
|
|
585
|
+
File.write(ldap_conf, content) unless content == File.read(ldap_conf)
|
|
410
586
|
end
|
|
411
587
|
end
|
|
412
588
|
end
|
data/lib/whimsy/asf/rack.rb
CHANGED
|
@@ -21,12 +21,12 @@ module ASF
|
|
|
21
21
|
def self.decode(env)
|
|
22
22
|
class << env; attr_accessor :user, :password; end
|
|
23
23
|
|
|
24
|
-
if env['HTTP_AUTHORIZATION']
|
|
24
|
+
if env['HTTP_AUTHORIZATION'].to_s.empty?
|
|
25
|
+
env.user = env['REMOTE_USER'] || ENV['USER'] || Etc.getpwuid.name
|
|
26
|
+
else
|
|
25
27
|
require 'base64'
|
|
26
28
|
env.user, env.password = Base64.decode64(env['HTTP_AUTHORIZATION'][
|
|
27
|
-
/^Basic ([A-Za-z0-9+\/=]+)$/,1]).split(':',2)
|
|
28
|
-
else
|
|
29
|
-
env.user = env['REMOTE_USER'] || ENV['USER'] || Etc.getpwuid.name
|
|
29
|
+
/^Basic ([A-Za-z0-9+\/=]+)$/,1].to_s).split(':',2)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
env['REMOTE_USER'] ||= env.user
|
|
@@ -189,6 +189,7 @@ module ASF
|
|
|
189
189
|
env['SCRIPT_URI'] += '/'
|
|
190
190
|
end
|
|
191
191
|
end
|
|
192
|
+
|
|
192
193
|
return @app.call(env)
|
|
193
194
|
end
|
|
194
195
|
end
|
data/lib/whimsy/asf/svn.rb
CHANGED
|
@@ -12,8 +12,9 @@ module ASF
|
|
|
12
12
|
|
|
13
13
|
def self.repos
|
|
14
14
|
@semaphore.synchronize do
|
|
15
|
-
svn = ASF::Config.get(:svn).map {|dir| dir.untaint}
|
|
15
|
+
svn = Array(ASF::Config.get(:svn)).map {|dir| dir.untaint}
|
|
16
16
|
@repos ||= Hash[Dir[*svn].map { |name|
|
|
17
|
+
next unless Dir.exist? name.untaint
|
|
17
18
|
Dir.chdir name.untaint do
|
|
18
19
|
out, err, status = Open3.capture3('svn', 'info')
|
|
19
20
|
if status.success?
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: whimsy-asf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.75
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sam Ruby
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-01-
|
|
11
|
+
date: 2016-01-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nokogiri
|
|
@@ -104,6 +104,8 @@ extra_rdoc_files: []
|
|
|
104
104
|
files:
|
|
105
105
|
- asf.gemspec
|
|
106
106
|
- asf.version
|
|
107
|
+
- lib/whimsy/asf.rb
|
|
108
|
+
- lib/whimsy/asf/agenda.rb
|
|
107
109
|
- lib/whimsy/asf/agenda/attachments.rb
|
|
108
110
|
- lib/whimsy/asf/agenda/back.rb
|
|
109
111
|
- lib/whimsy/asf/agenda/committee.rb
|
|
@@ -111,7 +113,6 @@ files:
|
|
|
111
113
|
- lib/whimsy/asf/agenda/front.rb
|
|
112
114
|
- lib/whimsy/asf/agenda/minutes.rb
|
|
113
115
|
- lib/whimsy/asf/agenda/special.rb
|
|
114
|
-
- lib/whimsy/asf/agenda.rb
|
|
115
116
|
- lib/whimsy/asf/auth.rb
|
|
116
117
|
- lib/whimsy/asf/bundler.rb
|
|
117
118
|
- lib/whimsy/asf/committee.rb
|
|
@@ -126,7 +127,6 @@ files:
|
|
|
126
127
|
- lib/whimsy/asf/site.rb
|
|
127
128
|
- lib/whimsy/asf/svn.rb
|
|
128
129
|
- lib/whimsy/asf/watch.rb
|
|
129
|
-
- lib/whimsy/asf.rb
|
|
130
130
|
homepage: https://whimsy.apache.org/
|
|
131
131
|
licenses:
|
|
132
132
|
- Apache License, Version 2.0
|
|
@@ -147,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
147
147
|
version: '0'
|
|
148
148
|
requirements: []
|
|
149
149
|
rubyforge_project:
|
|
150
|
-
rubygems_version: 2.
|
|
150
|
+
rubygems_version: 2.5.1
|
|
151
151
|
signing_key:
|
|
152
152
|
specification_version: 4
|
|
153
153
|
summary: Whimsy 'model' of the ASF
|