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 |
- |
|