0001-Send-DN-in-host-signed-token-instead-of-password-dig.patch

Ted Hesselroth, 06/13/2011 08:32 PM

Download (9.15 KB)

View differences:

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
-