0001-Send-DN-in-host-signed-token-instead-of-password-dig.patch
src/authm_mad/x509_auth.rb | ||
---|---|---|
276 | 276 |
public_key = extract_public_key(cert) |
277 | 277 |
# Decrypt the signed text with the public key |
278 | 278 |
decrypted=decrypt(special_token, public_key) |
279 |
username, subjn_digest, time, last =decrypted.split(':')
|
|
279 |
username, subjectname, time, last =decrypted.split(':')
|
|
280 | 280 |
if last # There was a : in the subjectname, from kerberos X509 credential |
281 | 281 |
subjectname = subjectname + ':' + time |
282 | 282 |
time = last |
... | ... | |
293 | 293 |
# Check the username |
294 | 294 |
raise "Login name " + username + " did not match username " + user + "." if user!=username |
295 | 295 |
|
296 |
# The user is authorized if their subject name has been set as their password. |
|
297 |
if user_id.to_i == 0 |
|
298 |
dn_digest = dn |
|
299 |
else |
|
300 |
# Compare digests. A digest is used instead of a plain DN because |
|
301 |
# it may not be possible to encrypt many '|'-separated DNs |
|
302 |
dn_digest = Digest::SHA1.hexdigest(dn) |
|
303 |
end |
|
304 | ||
305 |
raise "Login DN hash " + subjn_digest + " did not match hash of user DN " + dn + ", which was " + dn_digest if subjn_digest!=dn_digest |
|
296 |
# The user is authorized if their subject name has been set as their password. |
|
297 |
dn_ok = dn.split('|').include?(subjectname.gsub(/\s/, '')) |
|
298 |
raise "Login DN " + subjectname + " did not match user DN " + dn if !dn_ok |
|
306 | 299 |
|
307 | 300 |
true |
308 | 301 |
else |
... | ... | |
326 | 319 |
subject_name = user_cert.subject.to_s |
327 | 320 |
failed = "Authentication failed for " + subject_name + "." |
328 | 321 | |
329 |
dn_ok = dn.split('|').include?(subject_name.gsub(/\s/, '')) |
|
330 |
if dn_ok |
|
331 |
ok = "true" |
|
332 |
else |
|
333 |
ok = "false" |
|
334 |
end |
|
335 |
#raise ok |
|
336 | ||
337 |
# Check that the user's DN has been added to the users database |
|
322 |
# Check that the user's DN has been added to the users database |
|
323 |
dn_ok = dn.split('|').include?(subject_name.gsub(/\s/, '')) |
|
338 | 324 |
unless dn_ok |
339 |
raise "User " + subject_name + " is not mapped in the user database. " + dn |
|
325 |
raise "User " + subject_name + " is not mapped in the user database. Found " + dn
|
|
340 | 326 |
end |
341 | 327 | |
342 | 328 |
# Extract the public key |
src/cloud/ec2/lib/EC2QueryServer.rb | ||
---|---|---|
134 | 134 |
cert_array.unshift('-----BEGIN CERTIFICATE-----').push('-----END CERTIFICATE-----') |
135 | 135 |
user_cert = cert_array.join("\n") |
136 | 136 |
user_cert = OpenSSL::X509::Certificate.new(user_cert) |
137 |
subject_name = user_cert.subject.to_s |
|
138 |
puts(subject_name) |
|
137 |
subjectname = user_cert.subject.to_s |
|
138 |
subjectname_nosp = subjectname.gsub(/\s/, '') |
|
139 |
puts(subjectname) |
|
139 | 140 |
rescue |
140 | 141 |
raise failed + "Could not create X509 certificate from " + user_cert |
141 | 142 |
end |
142 | 143 |
|
143 |
# Password should be DN with whitespace removed. |
|
144 |
password = subject_name.gsub(/\s/, '') |
|
144 |
# Check that the DN corresponds to the password of a user |
|
145 | 145 |
begin |
146 |
username = get_username(password) |
|
147 |
puts("The username is " + username) |
|
148 |
password = get_user_password(username) |
|
146 |
username = get_username(subjectname_nosp) |
|
147 |
puts("The username is " + username) |
|
149 | 148 |
rescue |
150 |
raise failed + "User with DN " + password + " not found."
|
|
149 |
raise failed + "User with DN " + subjectname + " not found."
|
|
151 | 150 |
end |
152 | 151 |
|
153 | 152 |
# Sign the message and compose the special login token |
... | ... | |
185 | 184 |
|
186 | 185 |
# Sign with timestamp |
187 | 186 |
time=Time.now.to_i+3600 |
188 |
# If multiple DNs are authorized for the user, the '|'-separated |
|
189 |
# DN list may be very long, too long to encrypt with the host key |
|
190 |
# So encrypt a digest of the password instead |
|
191 |
passwd_digest = Digest::SHA1.hexdigest(password) |
|
192 |
text_to_sign="#{username}:#{passwd_digest}:#{time}" |
|
187 |
text_to_sign="#{username}:#{subjectname}:#{time}" |
|
193 | 188 |
puts "signing " + text_to_sign |
194 | 189 |
|
195 | 190 |
begin |
196 | 191 |
special_token=Base64::encode64(rsa.private_encrypt(text_to_sign)).gsub!(/\n/, '').strip |
197 | 192 |
rescue |
198 |
raise failed + "Could not create host-signed token for " + password
|
|
193 |
raise failed + "Could not create host-signed token for " + subjectname
|
|
199 | 194 |
end |
200 | 195 |
|
201 | 196 |
puts special_token |
src/sunstone/models/SunstoneServer.rb | ||
---|---|---|
105 | 105 |
cert_array.unshift('-----BEGIN CERTIFICATE-----').push('-----END CERTIFICATE-----') |
106 | 106 |
user_cert = cert_array.join("\n") |
107 | 107 |
user_cert = OpenSSL::X509::Certificate.new(user_cert) |
108 |
subject_name = user_cert.subject.to_s |
|
108 |
subjectname = user_cert.subject.to_s |
|
109 |
subjectname_nosp = subjectname.gsub(/\s/, '') |
|
109 | 110 |
rescue |
110 | 111 |
return [401, failed + "Could not create X509 certificate from " + user_cert] |
111 | 112 |
end |
112 | 113 | |
113 | 114 | |
114 |
# Password should be DN with whitespace removed. |
|
115 |
password = subject_name.gsub(/\s/, '') |
|
116 | ||
115 |
# Check that the DN corresponds to the password of a user |
|
117 | 116 |
begin |
118 |
username = user_pool["USER[PASSWORD=\"#{password}\"]/NAME"]
|
|
119 |
if (username == nil) |
|
117 |
username = user_pool["USER[PASSWORD=\"#{subjectname_nosp}\"]/NAME"]
|
|
118 |
if (username == nil)
|
|
120 | 119 |
|
121 |
# Check if the DN is part of a |-separted multi-DN password |
|
122 |
user_elts = Array.new |
|
123 |
user_pool.each {|e| user_elts << e['PASSWORD']} |
|
124 |
multiple_users = user_elts.select {|e| e=~ /\|/ } |
|
125 |
matched = nil |
|
126 |
multiple_users.each do |e| |
|
127 |
e.to_s.split('|').each do |w| |
|
128 |
if (w == password) |
|
129 |
matched=e |
|
130 |
break |
|
120 |
# Check if the DN is part of a |-separted multi-DN password |
|
121 |
user_elts = Array.new |
|
122 |
user_pool.each {|e| user_elts << e['PASSWORD']} |
|
123 |
multiple_users = user_elts.select {|e| e=~ /\|/ } |
|
124 |
matched = nil |
|
125 |
multiple_users.each do |e| |
|
126 |
e.to_s.split('|').each do |w| |
|
127 |
if (w == subjectname_nosp) |
|
128 |
matched=e |
|
129 |
break |
|
130 |
end |
|
131 | 131 |
end |
132 |
end |
|
133 |
break if matched |
|
134 |
end |
|
135 |
if matched |
|
136 |
password = matched.to_s |
|
137 |
end |
|
138 |
username = user_pool["USER[PASSWORD=\"#{password}\"]/NAME"] |
|
139 |
end |
|
140 |
|
|
132 |
break if matched |
|
133 |
end |
|
134 |
if matched |
|
135 |
password = matched.to_s |
|
136 |
end |
|
137 |
username = user_pool["USER[PASSWORD=\"#{password}\"]/NAME"] |
|
138 |
end |
|
141 | 139 |
rescue |
142 |
return [401, failed + "User with DN " + password + " not found."]
|
|
140 |
return [401, failed + "User with DN " + subjectname + " not found."]
|
|
143 | 141 |
end |
144 | 142 |
|
145 | 143 |
config = self.load_config |
... | ... | |
152 | 150 |
rescue |
153 | 151 |
return [401, failed + "Could not read " + hostkey_path] |
154 | 152 |
end |
153 |
|
|
155 | 154 |
begin |
156 | 155 |
host_cert_array=host_cert.split("\n") |
157 | 156 |
begin_lines=host_cert_array.select{|l| l.match(/BEGIN RSA PRIVATE KEY/)} |
... | ... | |
176 | 175 | |
177 | 176 |
# Sign with timestamp |
178 | 177 |
time=Time.now.to_i+7*24*3600 |
179 |
passwd_digest = Digest::SHA1.hexdigest(password) |
|
180 |
text_to_sign="#{username}:#{passwd_digest}:#{time}" |
|
178 |
text_to_sign="#{username}:#{subjectname}:#{time}" |
|
181 | 179 |
begin |
182 | 180 |
special_token=Base64::encode64(rsa.private_encrypt(text_to_sign)).gsub!(/\n/, '').strip |
183 | 181 |
rescue |
184 |
return [401, failed + "Could not create host-signed token for " + password]
|
|
182 |
return [401, failed + "Could not create host-signed token for " + subjectname]
|
|
185 | 183 |
end |
186 | 184 | |
187 | 185 |
return [204, user_pool["USER[NAME=\"#{username}\"]/ID"], "#{username}", "host-signed:#{special_token}}"] |
188 |
#return one_client_user(username, "host-signed:#{special_token}}") |
|
189 | 186 |
end |
190 | 187 | |
191 | 188 |
end |
192 |
- |